1800 lines
No EOL
73 KiB
JavaScript
1800 lines
No EOL
73 KiB
JavaScript
//========================================
|
||
// TF_LayeredMap.js
|
||
// Version :1.0.4.0
|
||
// For : RPGツクールMV (RPG Maker MV)
|
||
// -----------------------------------------------
|
||
// Copyright : Tobishima-Factory 2018 - 2020
|
||
// Website : http://tonbi.jp
|
||
//
|
||
// This software is released under the MIT License.
|
||
// http://opensource.org/licenses/mit-license.php
|
||
//========================================
|
||
/*:
|
||
* @plugindesc Upper[☆]tile display like billboard.
|
||
* @author Tonbi@Tobishima-Factory
|
||
*
|
||
*
|
||
* @param BillboardPriority
|
||
* @type select
|
||
* @option Put it front
|
||
* @value front
|
||
* @option Put it back
|
||
* @value back
|
||
* @desc Put billboard in front or back.
|
||
* @default back
|
||
*
|
||
*
|
||
* @param Autotile
|
||
*
|
||
* @param FillWithNeighborTile
|
||
* @type boolean
|
||
* @on Fill with neighbor tile
|
||
* @off Default lower tile
|
||
* @desc Fill with neighbor tile.It is function for A3 or A4 tile.
|
||
* @default true
|
||
* @parent Autotile
|
||
*
|
||
* @param DefaultLowerTile
|
||
* @type number
|
||
* @min 0
|
||
* @max 127
|
||
* @desc If FillWithNeighborTile option is OFF, fill with this tile.
|
||
* Start with 0 at upper left A5 to right.
|
||
* @default 16
|
||
* @parent Autotile
|
||
*
|
||
* @param UseLayeredCounter
|
||
* @type boolean
|
||
* @on Layered counter
|
||
* @off Normal
|
||
* @desc Counter becomes layered.
|
||
* A2 counter tile can layered like billboard.
|
||
* (HalfMove.js is needed)
|
||
* @default true
|
||
* @parent Autotile
|
||
*
|
||
* @param IsA2FullCollision
|
||
* @type boolean
|
||
* @on Full collision
|
||
* @off Closed and inside is accessible
|
||
* @desc Entire tile on the ground(A2) collision to activate.
|
||
* @default false
|
||
* @parent Autotile
|
||
*
|
||
* @param IsA3UpperOpen
|
||
* @type boolean
|
||
* @on Open
|
||
* @off Close
|
||
* @desc Remove the south collision of the roof(A3)?
|
||
* @default false
|
||
* @parent Autotile
|
||
*
|
||
* @param IsA4UpperOpen
|
||
* @type boolean
|
||
* @on Open
|
||
* @off Close
|
||
* @desc Remove the south collision of the wall top(A4)?
|
||
* @default false
|
||
* @parent Autotile
|
||
*
|
||
*
|
||
* @param Overpass
|
||
*
|
||
* @param OverpassTerrainTag
|
||
* @type number
|
||
* @min 0
|
||
* @max 7
|
||
* @desc Terraing tag for overpass tile.
|
||
* @default 3
|
||
* @parent Overpass
|
||
*
|
||
* @param CharacterSize
|
||
* @type select
|
||
* @option 1tile size
|
||
* @value 1
|
||
* @option 2tile size
|
||
* @value 2
|
||
* @desc Collision of overpass for.
|
||
* @default 1
|
||
* @parent Overpass
|
||
*
|
||
*
|
||
* @help
|
||
* Alert !!
|
||
* If you use HalfMove.js by Triacontane.Place HalfMove.js before TF_LayeredMap.js.
|
||
* And Place TF_LayeredMap.js before TF_Undulation.js.
|
||
*
|
||
* This plug-in provides the following functions.
|
||
* 1. [☆]+[4 direction pass] Billboard function for B〜E tile is added.
|
||
* 2. [TerrainTag] Crosspass function for B〜E tile is added.
|
||
* 3. [Counter] Billboard function for auto tile is added.
|
||
* 4. [TerrainTag] Auto tile collision and overpass function for bridge is added.
|
||
* 5. [Counter] [TerrainTag] Upper auto tile overpass function is added.
|
||
* 6. [TerrainTag] [×] The wall top that does not walk for A4 upper tile is added.
|
||
* 7. [TerrainTag] A5 tile up one layer.
|
||
* 8. <TF_zDef:Number> Put this tag in the note in event and adjust the overlap.
|
||
* 9. <TF_higherLevel:Boolean> Put this tag in the note in event and set overpass higher level.
|
||
*
|
||
* 1. set [☆] to BCDE tile, and set 4 direction setting.
|
||
* 0x0 ↑→←↓ : [☆] Same as no plugin.
|
||
* 0x1 ↑→←・ : billboard, ↑ ←→ pass, ground (for fence)
|
||
* 0x2 ↑→・↓ : billboard, ↑↓ → pass, ground (left side of fence)┃
|
||
* 0x3 ↑→・・ : billboard, ↑ → pass, ground (bottom left)┗
|
||
* 0x4 ↑・←↓ : billboard, ↑↓← pass, ground (right) ┃
|
||
* 0x5 ↑・←・ : billboard, ↑ ← pass, ground (bottom right) ┛
|
||
* 0x6 ↑・・↓ : billboard, ↑↓ pass, ground (both side)┃┃
|
||
* 0x7 ↑・・・ : billboard, ↑ pass, ground (like bartizan)┗┛
|
||
* 0x8 ・→←↓ : billboard, all directtion , ground (for bush)
|
||
* 0x9 ・→←・ : billboard, all directtion , 2nd floor
|
||
* 0xA ・→・↓ : billboard, all directtion , 3rd floor
|
||
* 0xB ・→・・ : Same as [○] and north half blocked (for lower shelf) (HalfMove.js is needed)
|
||
* 0xC ・・←↓ : Same as 0x1 and south half blocked (for Barrel) (HalfMove.js is needed)
|
||
* 0xD ・・←・ : Same as 0xB and collision is half (for lower tree) (HalfMove.js is needed)
|
||
* 0xE ・・・↓ : Same as 0xC and collision is half (for chair) (HalfMove.js is needed)
|
||
* 0xF ・・・・ : Same as 0x1 and collision is half (for peg)(HalfMove.js is needed)
|
||
*
|
||
* 2. Set TerrainTag to 3(default)
|
||
* If you enter from blocke direction, you can move under the tile.
|
||
* If you enter from pass direction, you can move over the tile.
|
||
*
|
||
* 3. For the clif.
|
||
* First, set [counter].
|
||
* A3・A4 odd line(roof・walltop)
|
||
* [○] All = upper[☆]
|
||
* A3・A4 even line(wallside)
|
||
* [○] All = billboard, South=can't pass.(floor height set automaticaly)
|
||
* Common to A3 and A4
|
||
* [×] North = billboard, Perimeter = can't pass.
|
||
*
|
||
* 4. For the bridge or the stairs.
|
||
* First, set [TerrainTag:3].
|
||
* A3 odd line(roof)
|
||
* [○] SouthNorth = can't pass, WestEast = pass.
|
||
* [×] SouthNorth = pass under、WestEast = pass over.
|
||
* A3・A4 even line(wallside)
|
||
* [○] SouthNorth = pass, WestEast = can't pass.
|
||
* [×] SouthNorth = pass over, WestEast = pass under.
|
||
*
|
||
* 5. For the overpass.
|
||
* First, set [counter][TerrainTag:3].
|
||
* A3・A4 odd line(roof・walltop)
|
||
* [○] All = overpass.
|
||
* [×] North = overpass, Perimeter = can't pass.
|
||
*
|
||
* 6. For the wall that does not walk on.
|
||
* A4 odd line(walltop)
|
||
* [TerrainTag:3][×] North = upper[☆], All = can't enter.
|
||
*
|
||
* 7. Move up one layer.
|
||
* Add [TerrainTag:3] to A5 tile, Set the tile at base layer and target tile up one layer.
|
||
* The overpass will not work. If the right side of A2 is on the target tile, it will gone.
|
||
*
|
||
* 8. adjust the overlap
|
||
* <TF_zDef:Number> Put this tag in the note in event.
|
||
* Add a number to the y position and set a virtual y position.
|
||
* Enter a number greater than 6 (default) to bring the character to the front.
|
||
*
|
||
* 9. set overpass higher level.
|
||
* <TF_higherLevel:Boolean> Put this tag in the note in event.
|
||
* true:front(upper)、false:back(lower)
|
||
* default:false
|
||
*
|
||
* Released under the MIT License.
|
||
*/
|
||
/*:ja
|
||
* @plugindesc 高層[☆]タイルを書き割り風に配置する
|
||
* @author とんび@鳶嶋工房
|
||
*
|
||
* @param BillboardPriority
|
||
* @type select
|
||
* @option 手前
|
||
* @value front
|
||
* @option 奥(規定値)
|
||
* @value back
|
||
* @text 奥行き優先度
|
||
* @desc 書き割りの奥・手前配置の設定
|
||
* @default back
|
||
*
|
||
*
|
||
* @param Autotile
|
||
* @text オートタイル
|
||
*
|
||
* @param FillWithNeighborTile
|
||
* @type boolean
|
||
* @on 周辺のタイル
|
||
* @off 補完用規定タイル
|
||
* @text 周辺のタイルでの補完
|
||
* @desc 低層(地面)を北(最南端は南)のタイルで補完するか
|
||
* @default true
|
||
* @parent Autotile
|
||
*
|
||
* @param DefaultLowerTile
|
||
* @type number
|
||
* @min 0
|
||
* @max 127
|
||
* @text 補完用規定タイル
|
||
* @desc [周辺のタイルでの補完]がOFFの場合に使う規定タイル
|
||
* 番号はA5左上を0として右への順。規定値:16(草原)
|
||
* @default 16
|
||
* @parent Autotile
|
||
*
|
||
* @param UseLayeredCounter
|
||
* @type boolean
|
||
* @text カウンター回り込み
|
||
* @on 回り込み
|
||
* @off 通常
|
||
* @desc A2のカウンターの後ろに回り込めるようにするか
|
||
* (HalfMove.js が必要)
|
||
* @default true
|
||
* @parent Autotile
|
||
*
|
||
* @param IsA2FullCollision
|
||
* @type boolean
|
||
* @on 通行止め
|
||
* @off 閉じて内側は通行可
|
||
* @text タイル全体を通行不可にするか
|
||
* @desc A2(地面)のタイル全体を通行不可にするか
|
||
* @default false
|
||
* @parent Autotile
|
||
*
|
||
* @param IsA3UpperOpen
|
||
* @type boolean
|
||
* @on 南を開く
|
||
* @off 閉じて内側は通行可
|
||
* @text 屋根南を開くか
|
||
* @desc A3(屋根)[周囲=通行不可]の場合に、南の衝突判定をなくすか
|
||
* @default false
|
||
* @parent Autotile
|
||
*
|
||
* @param IsA4UpperOpen
|
||
* @type boolean
|
||
* @on 南を開く
|
||
* @off 閉じて内側は通行可
|
||
* @text 壁上面南を開くか
|
||
* @desc A4(壁上上面)[周囲=通行不可]の場合に、南の衝突判定をなくすか
|
||
* @default false
|
||
* @parent Autotile
|
||
*
|
||
*
|
||
* @param Overpass
|
||
* @text 立体交差
|
||
*
|
||
* @param OverpassTerrainTag
|
||
* @type number
|
||
* @min 0
|
||
* @max 7
|
||
* @text 立体交差の地形タグ
|
||
* @desc 立体交差不使用 : 0
|
||
* 立体交差をさせたいタイルに指定する地形タグ
|
||
* @default 3
|
||
* @parent Overpass
|
||
*
|
||
* @param CharacterSize
|
||
* @type select
|
||
* @option 1tile size
|
||
* @value 1
|
||
* @option 2tile size
|
||
* @value 2
|
||
* @desc Collision of overpass for.
|
||
* @text キャラのタイルサイズ
|
||
* @desc 立体交差の衝突判定用のキャラサイズ
|
||
* @default 1
|
||
* @parent Overpass
|
||
*
|
||
*
|
||
* @help
|
||
* 注意 : トリアコンタンさんの HalfMove.js を利用する場合は。
|
||
* TF_LayeredMap.js の前に HalfMove.js を配置するようにしてください。
|
||
* TF_Undulation.js と一緒の場合は、TF_LayeredMap.js が前です。
|
||
*
|
||
* このプラグインは以下の機能を提供します。
|
||
* 1. [☆]+[通行設定(4方向)]で、B〜Eタイルの重なり機能を追加。
|
||
* 2. [地形タグ]で、B〜Eタイルの立体交差機能を追加。
|
||
* 3. [カウンター]で、A3・A4タイルに回り込み機能を追加。
|
||
* 4. [地形タグ]で、A3・A4タイルに橋の衝突判定と立体交差機能を追加。
|
||
* 5. [カウンター] [地形タグ] で、A3・A4タイル上面に立体交差機能を追加。
|
||
* 6. [地形タグ] [×] で、A4上面タイルに上を歩かない壁用の設定。
|
||
* 7. [地形タグ]で、A5タイルをひとつ上のレイヤーに移動。
|
||
* 8. <TF_zDef:数値> をイベントのメモに記入して重なりの調整。
|
||
* 9. <TF_higherLevel:真偽値> をイベントのメモに記入して立体交差の奥手前の指定。
|
||
* 10. TF_HIGHER_LEVEL コマンドで立体交差の奥手前の指定。
|
||
*
|
||
* 1. B〜Eタイルに[☆]を指定したあと、[通行設定(4方向)]
|
||
* 0x0 ↑→←↓ : [☆] 設定、全方向に 通行可(プラグインなしと同じ)
|
||
* 0x1 ↑→←・ : 書き割り、北 西東 通行可、1階 【基本、柵とか】
|
||
* 0x2 ↑→・↓ : 書き割り、北南 東 通行可、1階 (柵の西側とか)┃
|
||
* 0x3 ↑→・・ : 書き割り、北 東 通行可、1階 (柵の西南とか)┗
|
||
* 0x4 ↑・←↓ : 書き割り、北南西 通行可、1階 (柵の東側とか) ┃
|
||
* 0x5 ↑・←・ : 書き割り、北 西 通行可、1階 (柵の東南とか) ┛
|
||
* 0x6 ↑・・↓ : 書き割り、北南 通行可、1階 (両脇に木とか)┃┃
|
||
* 0x7 ↑・・・ : 書き割り、北 通行可、1階 (張り出し的な)┗┛
|
||
* 0x8 ・→←↓ : 書き割り、全方向に 通行可、1階 (草むらなどに)
|
||
* 0x9 ・→←・ : 書き割り、全方向に 通行可、2階
|
||
* 0xA ・→・↓ : 書き割り、全方向に 通行可、3階
|
||
* 0xB ・→・・ : 地面[○] 設定かつ北半分通行不可 (棚などに)(HalfMove.js が必要)
|
||
* 0xC ・・←↓ : 0x1 と同じだが南半分が通行不可 (机などに)(HalfMove.js が必要)
|
||
* 0xD ・・←・ : 0xB と同じだが北の両脇が通行可 (根元とか)(HalfMove.js が必要)
|
||
* 0xE ・・・↓ : 0xC と同じだが南の両脇が通行可 (椅子とか)(HalfMove.js が必要)
|
||
* 0xF ・・・・ : 0x1 と同じだが南の両脇が通行可 (杭などに)(HalfMove.js が必要)
|
||
*
|
||
* 2. [地形タグ]を3(規定値)に設定
|
||
* 通行設定で侵入可の方向から入ると上を通ります。
|
||
* 侵入不可の方向から入ると下を通ります。
|
||
*
|
||
* 3. 崖など回り込み用
|
||
* [カウンター]設定
|
||
* A3・A4の奇数列(屋根・壁上面)
|
||
* [○] 全体=高層[☆]
|
||
* A3・A4の偶数列(壁)
|
||
* [○] 全体=回り込み、南方向は通行不可(壁の高さは自動調整)
|
||
* A3・A4に共通
|
||
* [×] 北=回り込み、周囲=通行不可
|
||
*
|
||
* 4. 橋の立体交差や階段用
|
||
* [地形タグ:3]設定
|
||
* A3の奇数列(屋根)
|
||
* [○]南北=通行不可、東西=通行
|
||
* [×]南北=下通行、東西=上通行(立体交差)
|
||
* A3・A4の偶数列(壁)
|
||
* [○]南北=通行、東西=通行不可
|
||
* [×]南北=上通行、東西=下通行(立体交差)
|
||
*
|
||
* 5. 立体交差
|
||
* [カウンター] [地形タグ:3] 設定
|
||
* A3・A4の奇数列(屋根・壁上面)
|
||
* [○]全面立体交差
|
||
* [×]北=立体交差、周囲=通行不可
|
||
*
|
||
* 6. 上を歩かない壁用の設定
|
||
* A4の奇数列(壁上面)
|
||
* [地形タグ:3][×] 北=高層[☆]、全面通行不可
|
||
*
|
||
* 7. ひとつ上のレイヤーに移動
|
||
* A5タイルに[地形タグ:3] で、背景を補完しA2右側レイヤーに移動。
|
||
* 立体交差は機能しないし、A2右側タイルがあれば消える。
|
||
*
|
||
* 8. 重ね合わせの順番を調節
|
||
* <TF_zDef:数値> をイベントのメモに入力。
|
||
* 数値はy位置に加えられて、仮想的にy位置をずらす。
|
||
* キャラ画像は標準環境でy方向に-6ずれているので、例えば8を入れると手前に表示される。
|
||
*
|
||
* 9. 立体交差の奥手前の指定
|
||
* <TF_higherLevel:真偽値> をイベントのメモに入力
|
||
* trueだと立体交差の手前(上)、falseだと奥(下)に配置される。
|
||
* 規定値はfalse。
|
||
*
|
||
* 10. プラグインコマンドで立体交差の奥手前の指定。
|
||
* TF_HIGHER_LEVEL 真偽値 対象(省略可)
|
||
* 対象は -2~-4:隊列キャラ、-1:プレイヤーキャラ、0:イベント自身(規定値)、1以降:イベントID
|
||
*
|
||
* 利用規約 : MITライセンス
|
||
*/
|
||
(function () {
|
||
'use strict';
|
||
const TF_HIGHER_LEVEL = 'TF_HIGHER_LEVEL';
|
||
|
||
// flag用定数
|
||
const FLAG_NORTH_DIR = 0x8; // 北の通行設定
|
||
const FLAG_UPPER = 0x10; // 高層[☆]
|
||
const FLAG_COUNTER = 0x80; // カウンター
|
||
// flagのマスク
|
||
const MASK_WITHOUT_DIR_UPPER = 0xFF60; // 方向と高層[☆]とカウンターを除いたもの用マスク
|
||
const MASK_WITHOUT_TAG_DIR_UPPER = 0xF60; // 方向と高層[☆]と地形タグとカウンターを除いたもの用マスク
|
||
const MASK_ALL_DIR = 0xF; // 通行設定用マスク
|
||
|
||
// 書割り設定
|
||
const FLOOR2_BOARD = 0x19; // 09 書き割り、全方向に 通行可、2階
|
||
const FLOOR3_BOARD = 0x1A; // 10 書き割り、全方向に 通行可、3階
|
||
|
||
const MASK_UPPER_DIR = 0x1F; // 高層[☆]と通行設定用マスク
|
||
const FLOOR1_N_FULL = 0x1B; // 11 棚
|
||
const FLOOR1_S_FULL = 0x1C; // 12 机
|
||
const FLOOR1_N_HALF = 0x1D; // 13 椅子(北)
|
||
const FLOOR1_S_HALF = 0x1E; // 14 椅子(南)
|
||
const FLOOR1_S_FLAT = 0x1F; // 15 杭
|
||
|
||
const AUTOTILE_BLOCK = 48; // オートタイル1ブロック分のパターン数
|
||
|
||
|
||
/*---- パラメータパース関数 ----*/
|
||
const PARAM_TRUE = 'true';
|
||
const PARAM_ON = 'on';
|
||
const TYPE_BOOLEAN = 'boolean';
|
||
const TYPE_NUMBER = 'number';
|
||
/**
|
||
* 指定したパラメータが、指定した値と同じか。
|
||
* @param {String} paramName パラメータ名
|
||
* @param {String} param 比較する値(小文字)
|
||
* @param {Boolean} defaultParam 規定値
|
||
* @returns {Boolean}
|
||
*/
|
||
function conpairPluginParam(paramName, param, defaultParam) {
|
||
if (pluginParams[paramName]) {
|
||
return pluginParams[paramName].toLowerCase() === param;
|
||
} else {
|
||
return defaultParam;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 与えられた文字列に変数が指定されていたら、変数の内容に変換して返す。
|
||
* @param {String} value 変換元の文字列( v[n]形式を含む )
|
||
* @return {String} 変換後の文字列
|
||
*/
|
||
function treatValue(value) {
|
||
if (value === undefined || value === '') return '0';
|
||
const result = value.match(/v\[(.+)\]/i);
|
||
if (result === null) return value;
|
||
const id = parseInt(result[1], 10);
|
||
if (isNaN(id)) {
|
||
return $gameVariables.valueByName(id);
|
||
} else {
|
||
return $gameVariables.value(id);
|
||
}
|
||
}
|
||
/*--- Game_Variables ---*/
|
||
/**
|
||
* 変数を文字列で指定し、値を返す。
|
||
* @param {String} name 変数(ID, 名前, V[n]による指定が可能)
|
||
*/
|
||
Game_Variables.prototype.valueByName = function (name) {
|
||
return this.value(stringToVariableId(name));
|
||
};
|
||
/**
|
||
* 指定された変数のIDを返す。
|
||
* @param {String} name 変数(ID, 名前, V[n]による指定が可能)
|
||
*/
|
||
function stringToVariableId(name) {
|
||
name = treatValue(name);
|
||
let i = $dataSystem.variables.findIndex(i => i === name);
|
||
if (0 <= i) return i;
|
||
i = parseInt(name, 10);
|
||
if (isNaN(i)) throw new Error(`I can't find the variable '${name}'`);
|
||
return i;
|
||
}
|
||
|
||
/**
|
||
* 文字列を整数に変換して返す。
|
||
* @param {String|Number} value
|
||
* @return {Number} 数値に変換した結果
|
||
*/
|
||
function parseIntStrict(value) {
|
||
if (typeof value === TYPE_NUMBER) return Math.floor(value);
|
||
const result = parseInt(treatValue(value), 10);
|
||
if (isNaN(result)) throw Error('指定した値[' + value + ']が数値ではありません。');
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 文字列を実数に変換して返す。
|
||
* @param {String|Number} value
|
||
* @return {Number} 数値に変換した結果
|
||
*/
|
||
function parseFloatStrict(value) {
|
||
if (typeof value === 'number') return value;
|
||
const result = parseFloat(treatValue(value));
|
||
if (isNaN(result)) throw Error('指定した値[' + value + ']が数値ではありません。');
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 文字列を真偽値に変換して返す。
|
||
* @param {String|Boolean} value 変換元文字列
|
||
* @returns {Boolean}
|
||
*/
|
||
function parseBooleanStrict(value) {
|
||
if (typeof value === TYPE_BOOLEAN) return value;
|
||
value = treatValue(value);
|
||
const result = value.toLowerCase();
|
||
return (result === PARAM_TRUE || result === PARAM_ON);
|
||
}
|
||
|
||
/**
|
||
* character を拡張して隊列メンバーも指定できるようにしたもの。
|
||
* @param {Game_Interpreter} interpreter インタプリタ
|
||
* @param {Number} id 拡張イベントID
|
||
* @returns {Game_CharacterBase}
|
||
*/
|
||
function getEventById(interpreter, id) {
|
||
if (id < -1) {
|
||
return $gamePlayer.followers().follower(-2 - id); // 隊列メンバー(0〜2)
|
||
} else {
|
||
return interpreter.character(id); // プレイヤーキャラおよびイベント
|
||
}
|
||
}
|
||
|
||
const EVENT_THIS = 'this';
|
||
const EVENT_SELF = 'self';
|
||
const EVENT_PLAYER = 'player';
|
||
const EVENT_FOLLOWER0 = 'follower0';
|
||
const EVENT_FOLLOWER1 = 'follower1';
|
||
const EVENT_FOLLOWER2 = 'follower2';
|
||
/**
|
||
* 文字列をイベントIDへ変換
|
||
* @param {String} value イベントIDの番号か識別子
|
||
* @returns {Number} 拡張イベントID
|
||
*/
|
||
function stringToEventId(value) {
|
||
value = treatValue(value);
|
||
const result = parseInt(value, 10);
|
||
if (!isNaN(result)) return result;
|
||
|
||
const lowValue = value.toLowerCase();
|
||
switch (lowValue) {
|
||
case EVENT_THIS:
|
||
case EVENT_SELF: return 0;
|
||
case EVENT_PLAYER: return -1;
|
||
case EVENT_FOLLOWER0: return -2;
|
||
case EVENT_FOLLOWER1: return -3;
|
||
case EVENT_FOLLOWER2: return -4;
|
||
}
|
||
|
||
// イベント名で指定できるようにする
|
||
const i = $gameMap._events.findIndex(event => {
|
||
if (event === undefined) return false; // _events[0] が undefined なので無視
|
||
|
||
const eventId = event._eventId;
|
||
return $dataMap.events[eventId].name === value;
|
||
});
|
||
if (i === -1) throw Error(`指定したイベント[${value}]がありません。`);
|
||
return i;
|
||
}
|
||
|
||
/**
|
||
* パラメータを受け取る
|
||
*/
|
||
const pluginParams = PluginManager.parameters('TF_LayeredMap');
|
||
const TF_FillWithNeighborTile = parseBooleanStrict(pluginParams.FillWithNeighborTile);
|
||
const TF_DefaultLowerTileId = Tilemap.TILE_ID_A5 + parseIntStrict(pluginParams.DefaultLowerTile);
|
||
const TF_UseLayeredCounter = parseBooleanStrict(pluginParams.UseLayeredCounter);
|
||
const TF_BillboardPriority = conpairPluginParam('BillboardPriority', 'front', false) ? Infinity : -Infinity;
|
||
const TF_IsA2FullCollision = parseBooleanStrict(pluginParams.IsA2FullCollision);
|
||
const TF_IsA3UpperOpen = parseBooleanStrict(pluginParams.IsA3UpperOpen);
|
||
const TF_IsA4UpperOpen = parseBooleanStrict(pluginParams.IsA4UpperOpen);
|
||
const TF_OverpassTerrainTag = parseIntStrict(pluginParams.OverpassTerrainTag);
|
||
const TF_CharacterSize = parseIntStrict(pluginParams.CharacterSize);
|
||
|
||
/*---- SceneManager ----*/
|
||
// URLでの指定がない限り、WebGL モードを採用する。
|
||
const MODE_CANVAS = 'canvas';
|
||
const MODE_WEBGL = 'webgl';
|
||
SceneManager.preferableRendererType = function () {
|
||
return (Utils.isOptionValid(MODE_CANVAS)) ? MODE_CANVAS : MODE_WEBGL;
|
||
};
|
||
|
||
/*---- Game_Interpreter ----*/
|
||
/**
|
||
* プラグインコマンドの実行
|
||
*/
|
||
const _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
|
||
Game_Interpreter.prototype.pluginCommand = function (command, args) {
|
||
_Game_Interpreter_pluginCommand.apply(this, arguments);
|
||
|
||
// _higherLevel のON/OFF
|
||
if (command.toUpperCase() !== TF_HIGHER_LEVEL) return;
|
||
|
||
const targetCharacter = getEventById(this, stringToEventId(args[1]));
|
||
targetCharacter._higherLevel = parseBooleanStrict(args[0]);
|
||
};
|
||
|
||
|
||
/*---- Tilemap ----*/
|
||
/**
|
||
* その位置が立体交差であるかチェック(地形タグで決定)
|
||
*/
|
||
const _Tilemap_isOverpassPosition = Tilemap.prototype._isOverpassPosition;
|
||
Tilemap.prototype._isOverpassPosition = function (x, y) {
|
||
if (TF_OverpassTerrainTag !== 0 && $gameMap.terrainTag(x, y) === TF_OverpassTerrainTag) return true;
|
||
return _Tilemap_isOverpassPosition.apply(this, arguments);
|
||
};
|
||
|
||
/**
|
||
* イベントの重なりのソート用関数。
|
||
*/
|
||
Tilemap.prototype._compareChildOrder = function (a, b) {
|
||
if (a.z !== b.z) return a.z - b.z;
|
||
const zDefA = a._character ? a._character._TF_zDef : 0;
|
||
const zDefB = b._character ? b._character._TF_zDef : 0;
|
||
const ay = a.y + (zDefA ? zDefA : 0);
|
||
const by = b.y + (zDefB ? zDefB : 0);
|
||
if (ay !== by) {
|
||
return ay - by;
|
||
}
|
||
return a.spriteId - b.spriteId;
|
||
};
|
||
|
||
/*---- ShaderTilemap ----*/
|
||
/**
|
||
* タイルセットの画像を設定する。
|
||
* マップ開始時に呼ばれる。
|
||
*/
|
||
const _ShaderTilemap_refreshTileset = ShaderTilemap.prototype.refreshTileset;
|
||
ShaderTilemap.prototype.refreshTileset = function () {
|
||
_ShaderTilemap_refreshTileset.call(this);
|
||
|
||
// BitmapをPIXI.Textureにコンバート
|
||
const bitmaps = this.bitmaps.map(function (x) {
|
||
return x._baseTexture ? new PIXI.Texture(x._baseTexture) : x;
|
||
});
|
||
|
||
// 書き割りのタイルセットの画像をアップデート
|
||
for (let curItem of this.TF_billboards) {
|
||
curItem.children[0].setBitmaps(bitmaps);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 書き割りレイヤーの生成と追加。
|
||
*/
|
||
const _ShaderTilemap_createLayers = ShaderTilemap.prototype._createLayers;
|
||
ShaderTilemap.prototype._createLayers = function () {
|
||
_ShaderTilemap_createLayers.call(this);
|
||
|
||
// 書き割り風オブジェクトを生成
|
||
// +3 はスクロールの際にはみ出す部分と2・3階用
|
||
const th = this._tileHeight;
|
||
const tileRows = Math.ceil(this._height / th) + 3;
|
||
|
||
if (!this.hasOwnProperty('TF_billboards')) {
|
||
this.TF_billboards = [];
|
||
}
|
||
|
||
for (let i = 0; i < tileRows; i++) {
|
||
const billboard = new PIXI.tilemap.ZLayer(this, 3);
|
||
billboard.spriteId = TF_BillboardPriority;
|
||
this.addChild(billboard);
|
||
this.TF_billboards.push(billboard);
|
||
const layer = new PIXI.tilemap.CompositeRectTileLayer(0, [], 0);
|
||
billboard.addChild(layer);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 描画前に書き割りの中を空にしておく。
|
||
*/
|
||
const _ShaderTilemap_paintAllTiles = ShaderTilemap.prototype._paintAllTiles;
|
||
ShaderTilemap.prototype._paintAllTiles = function (startX, startY) {
|
||
for (let curItem of this.TF_billboards) {
|
||
curItem.clear();
|
||
}
|
||
|
||
_ShaderTilemap_paintAllTiles.apply(this, arguments);
|
||
};
|
||
|
||
/**
|
||
* タイルマップと書き割りの描画。
|
||
* 関数をまるっと書き換えているので
|
||
* 他のプラグインとコンフリクトを起こしてしまうので注意。
|
||
* @param {Number} startX 開始 マップ x座標(タイル数)
|
||
* @param {Number} startY 開始 マップ y座標(タイル数)
|
||
* @param {Number} x 画面上の x座標(タイル数)
|
||
* @param {Number} y 画面上の y座標(タイル数)
|
||
*/
|
||
ShaderTilemap.prototype._paintTiles = function (startX, startY, x, y) {
|
||
const mx = startX + x; // 描画対象のマップ x座標(タイル数)
|
||
const my = startY + y; // 描画対象のマップ y座標(タイル数)
|
||
const dx = x * this._tileWidth; // 描画位置の x座標(ピクセル)
|
||
const dy = y * this._tileHeight; // 描画位置の y座標(ピクセル)
|
||
const tileId0 = this._readMapData(mx, my, 0); // 低層タイルA
|
||
const tileId1 = this._readMapData(mx, my, 1); // 低層タイルA2右側など
|
||
const tileId2 = this._readMapData(mx, my, 2); // B 〜 E タイル
|
||
const tileId3 = this._readMapData(mx, my, 3); // B 〜 E タイル
|
||
const shadowBits = this._readMapData(mx, my, 4); // 影ペン
|
||
const northTileId1 = this._readMapData(mx, my - 1, 1); // 北位置の低層タイルA
|
||
const lowerLayer = this.lowerLayer.children[0]; // 低層レイヤ( z: 0 )
|
||
const upperLayer = this.upperLayer.children[0]; // 高層レイヤ( z: 4 )
|
||
|
||
/**
|
||
* タイルを描画(upperLayer,lowerLayer,dx,dy は親の変数を使う)
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
const drawTile = (tileId) => {
|
||
if (!this._isHigherTile(tileId)
|
||
|| (this.flags[tileId] & MASK_UPPER_DIR) === FLOOR1_N_FULL
|
||
|| (this.flags[tileId] & MASK_UPPER_DIR) === FLOOR1_N_HALF
|
||
) {
|
||
// 高層タイルではない
|
||
this._drawTile(lowerLayer, tileId, dx, dy);
|
||
return;
|
||
}
|
||
|
||
// 優先階(priorityFloor)を設定
|
||
let priorityFloor;
|
||
if ((this.flags[tileId] & MASK_UPPER_DIR) === FLOOR2_BOARD) {
|
||
priorityFloor = 2;
|
||
} else if ((this.flags[tileId] & MASK_UPPER_DIR) === FLOOR3_BOARD) {
|
||
priorityFloor = 3;
|
||
} else {
|
||
priorityFloor = 1;
|
||
}
|
||
|
||
let floorNumber = 1;
|
||
if (priorityFloor === 2 || priorityFloor === 3) {
|
||
const wallSideType = getWallSideType(this._readMapData(mx, my + 1, 1));
|
||
|
||
if (wallSideType === 1) {
|
||
floorNumber = 2;
|
||
} else if (wallSideType === 2) {
|
||
floorNumber = 3;
|
||
} else if (wallSideType === 3) {
|
||
floorNumber = priorityFloor;
|
||
} else {
|
||
// 壁ではない場合
|
||
floorNumber = priorityFloor;
|
||
// TODO : B〜E タイルのオート位置設定を行う…か?
|
||
}
|
||
}
|
||
|
||
if (floorNumber === 2) {
|
||
// 2階設定は、ひとつ下の書き割りに書き込む
|
||
this._drawTile(this.TF_billboards[y + 1].children[0].children[0], tileId, dx, -this._tileHeight * 2);
|
||
|
||
} else if (floorNumber === 3) {
|
||
// 3階設定は、ふたつ下の書き割りに書き込む
|
||
this._drawTile(this.TF_billboards[y + 2].children[0].children[0], tileId, dx, -this._tileHeight * 3);
|
||
|
||
} else if (this.flags[tileId] & MASK_ALL_DIR) {
|
||
// 通行不可設定のどれかがONだと書き割り
|
||
this._drawTile(this.TF_billboards[y].children[0].children[0], tileId, dx, -this._tileHeight);
|
||
|
||
} else {
|
||
// 全方向通行可の場合は通常の高層[☆]表示
|
||
this._drawTile(upperLayer, tileId, dx, dy);
|
||
}
|
||
};
|
||
|
||
drawTile(tileId0);
|
||
drawTile(tileId1);
|
||
|
||
// 影の描画
|
||
this._drawShadow(lowerLayer, shadowBits, dx, dy);
|
||
|
||
// テーブルの描画
|
||
if (this._isTableTile(northTileId1) && !this._isTableTile(tileId1)) {
|
||
if (!Tilemap.isShadowingTile(tileId0) && !Tilemap.isShadowingTile(tileId1)) {
|
||
this._drawTableEdge(lowerLayer, northTileId1, dx, dy);
|
||
}
|
||
}
|
||
|
||
// 立体交差の描画
|
||
if (this._isOverpassPosition(mx, my)) {
|
||
this._drawTile(upperLayer, tileId2, dx, dy);
|
||
this._drawTile(upperLayer, tileId3, dx, dy);
|
||
} else {
|
||
drawTile(tileId2);
|
||
drawTile(tileId3);
|
||
}
|
||
|
||
/**
|
||
* 指定位置の壁の状態を調べる。
|
||
* @param {Number} tileId タイルID
|
||
* @returns {Number} 0:壁ではない, 1:下端, 2:上下に接続した壁, 3:上端
|
||
*/
|
||
function getWallSideType(tileId) {
|
||
if (!Tilemap.isWallSideTile(tileId)) return 0; // 壁タイルではない
|
||
|
||
// autotileShape のビットは 下右上左 に対応しているので、それで判定
|
||
const autotileShape = Tilemap.getAutotileShape(tileId);
|
||
if (autotileShape & 2) return 3;
|
||
if (autotileShape & 8) return 1;
|
||
return 2;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* (スクロールに合わせて)書き割りの表示位置を変更。
|
||
* @param {Number} startX
|
||
* @param {Number} startY
|
||
*/
|
||
const _ShaderTilemap_updateLayerPositions = ShaderTilemap.prototype._updateLayerPositions;
|
||
ShaderTilemap.prototype._updateLayerPositions = function (startX, startY) {
|
||
_ShaderTilemap_updateLayerPositions.apply(this, arguments);
|
||
|
||
let ox, oy;
|
||
if (this.roundPixels) {
|
||
ox = Math.floor(this.origin.x);
|
||
oy = Math.floor(this.origin.y);
|
||
} else {
|
||
ox = this.origin.x;
|
||
oy = this.origin.y;
|
||
}
|
||
const th = this._tileHeight;
|
||
const tw = this._tileWidth;
|
||
const posX = startX * tw - ox;
|
||
const posY = startY * th - oy;
|
||
const l = this.TF_billboards.length;
|
||
for (let i = 0; i < l; i++) {
|
||
const curItem = this.TF_billboards[i];
|
||
curItem.position.x = posX;
|
||
curItem.position.y = posY + (i + 1) * th;
|
||
};
|
||
};
|
||
|
||
/*---- DataManager ---*/
|
||
/**
|
||
* 読み込み直後に、タイルセットデータを書き換える。
|
||
* @param {Object} object 読み込んだデータ
|
||
*/
|
||
const _DataManager_onLoad = DataManager.onLoad;
|
||
DataManager.onLoad = function (object) {
|
||
_DataManager_onLoad.apply(this, arguments);
|
||
if (object !== $dataTilesets) return;
|
||
|
||
// 全タイルセットに対してflagの走査・変更
|
||
for (const curTileset of $dataTilesets) {
|
||
if (!curTileset) continue;
|
||
treatA2Tilesets(curTileset.flags);
|
||
treatA3Tilesets(curTileset.flags);
|
||
treatA4Tilesets(curTileset.flags);
|
||
}
|
||
};
|
||
/* ---- DataManager.onLoad 用ユーティリティ ---- */
|
||
// $gameMap が無い段階なので、必要な関数を代わりに定義したり、flags をまる渡ししたりしてる
|
||
|
||
const OPTT = (TF_OverpassTerrainTag << 12); // 立体交差地形タグ
|
||
|
||
/**
|
||
* カウンター設定か。
|
||
* @param {Number} tileFlag タイルのフラグ情報
|
||
*/
|
||
function isCounterTile(tileFlag) {
|
||
return (tileFlag & FLAG_COUNTER) === FLAG_COUNTER;
|
||
}
|
||
/**
|
||
* 指定タイルが立体交差地形タグを持っているか。
|
||
* @param {Number} tileFlag タイルのフラグ情報
|
||
*/
|
||
function isOverpassTile(tileFlag) {
|
||
if (TF_OverpassTerrainTag === 0) return false;
|
||
return tileFlag >> 12 === TF_OverpassTerrainTag;
|
||
}
|
||
|
||
/**
|
||
* 指定タイルが全方位に衝突判定を持っているか。
|
||
* @param {Number} tileFlag タイルのフラグ情報
|
||
*/
|
||
function isFullCollisionTile(tileFlag) {
|
||
return MASK_ALL_DIR === (tileFlag & MASK_ALL_DIR);
|
||
}
|
||
/**
|
||
* 指定タイルが衝突判定を持っているか。
|
||
* @param {Number} tileFlag タイルのフラグ情報
|
||
*/
|
||
function isCollisionTile(tileFlag) {
|
||
return 0 < (tileFlag & MASK_ALL_DIR);
|
||
}
|
||
|
||
// A2タイルの走査・変更。
|
||
function treatA2Tilesets(flags) {
|
||
for (let tileId = Tilemap.TILE_ID_A2; tileId < Tilemap.TILE_ID_A3; tileId += AUTOTILE_BLOCK) {
|
||
const autotileFlags =
|
||
(isCounterTile(flags[tileId]) ? 2 : 0) +
|
||
(isCollisionTile(flags[tileId + 46]) ? 1 : 0);
|
||
switch (autotileFlags) {
|
||
case 1: if (!TF_IsA2FullCollision) { setEmptyLinePass(flags, tileId); }; break; // [×]
|
||
case 3: if (TF_UseLayeredCounter) { setCounterPass(flags, tileId); }; break; // [×][♢]
|
||
}
|
||
}
|
||
}
|
||
|
||
// A3タイルの走査・変更。
|
||
function treatA3Tilesets(flags) {
|
||
for (let tileId = Tilemap.TILE_ID_A3; tileId < Tilemap.TILE_ID_A4; tileId += AUTOTILE_BLOCK) {
|
||
const autotileFlags =
|
||
(Tilemap.isRoofTile(tileId) ? 8 : 0) +
|
||
(isOverpassTile(flags[tileId]) ? 4 : 0) +
|
||
(isCounterTile(flags[tileId]) ? 2 : 0) +
|
||
(isCollisionTile(flags[tileId + 15]) ? 1 : 0);
|
||
switch (autotileFlags) {
|
||
// 側面
|
||
case 2: setWallSidePass(flags, tileId); break; // [○][♢]
|
||
case 3: setWallSideEdgePass(flags, tileId); break; // [×][♢]
|
||
case 4: setBridgeSNPass(flags, tileId, false); break; // [○][TT]
|
||
case 5: setBridgeSNPass(flags, tileId, true); break; // [×][TT]
|
||
// case 6 : ; break; // [○][♢][TT]
|
||
// case 7 : ; break; // [×][♢][TT]
|
||
|
||
// 上面
|
||
case 9: setRoofBottomPass(flags, tileId); break; // [×]
|
||
case 10: setAutoUpperPass(flags, tileId, 16); break; // [○][♢]
|
||
case 11: setRoofUpperPass(flags, tileId); break; // [×][♢]
|
||
case 12: setBridgeWEPass(flags, tileId, false); break; // [○][TT]
|
||
case 13: setBridgeWEPass(flags, tileId, true); break; // [×][TT]
|
||
case 14: setEmptySquarePass(flags, tileId); break; // [○][♢][TT]
|
||
case 15: setA3UpperOverPass(flags, tileId); break; // [×][♢][TT]
|
||
}
|
||
}
|
||
}
|
||
|
||
// A4タイルの走査・変更。
|
||
function treatA4Tilesets(flags) {
|
||
for (let tileId = Tilemap.TILE_ID_A4; tileId < Tilemap.TILE_ID_MAX; tileId += AUTOTILE_BLOCK) {
|
||
const autotileFlags =
|
||
(Tilemap.isWallTopTile(tileId) ? 8 : 0) +
|
||
(isOverpassTile(flags[tileId]) ? 4 : 0) +
|
||
(isCounterTile(flags[tileId]) ? 2 : 0) +
|
||
(isCollisionTile(flags[tileId + 46]) ? 1 : 0);
|
||
switch (autotileFlags) {
|
||
// 側面
|
||
case 2: setWallSidePass(flags, tileId); break; // [○][♢]
|
||
case 3: setWallSideEdgePass(flags, tileId); break; // [×][♢]
|
||
case 4: setBridgeSNPass(flags, tileId, false); break; // [○][TT]
|
||
case 5: setBridgeSNPass(flags, tileId, true); break; // [×][TT]
|
||
// case 6 : ; break; // [○][♢][TT]
|
||
// case 7 : ; break; // [×][♢][TT]
|
||
|
||
// 上面
|
||
case 9: if (!TF_IsA4UpperOpen) { setEmptyLinePass(flags, tileId); } break; // [×]
|
||
case 10: setAutoUpperPass(flags, tileId, 47); break; // [○][♢]
|
||
case 11: setA4UpperPass(flags, tileId); break; // [×][♢]
|
||
// case 12 : ; break; // [○][TT]
|
||
case 13: setA4UpperStarPass(flags, tileId); break; // [×][TT]
|
||
case 14: setEmptyLinePass(flags, tileId); break; // [○][♢][TT]
|
||
case 15: setA4UpperOverPass(flags, tileId); break; // [×][♢][TT]
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 衝突判定を指定した設定に変換。
|
||
* @param {Array} flags
|
||
* @param {Number} tileId
|
||
* @param {Number} mask flagのマスク
|
||
* @param {Array} collisionSetting 適用するflag設定
|
||
*/
|
||
function replaceCollision(flags, tileId, mask, collisionSetting) {
|
||
const maxNum = collisionSetting.length;
|
||
for (let i = 0; i < maxNum; i++) {
|
||
flags[tileId + i] = flags[tileId + i] & mask | collisionSetting[i];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 高層[☆] 全通行に変更。
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
* @param {Number} maxNum 変更数
|
||
*/
|
||
function setAutoUpperPass(flags, tileId, maxNum) {
|
||
for (let i = 0; i < maxNum; i++) {
|
||
flags[tileId + i] = flags[tileId + i] & MASK_WITHOUT_DIR_UPPER | FLAG_UPPER;
|
||
}
|
||
}
|
||
/**
|
||
* カウンター用に変更。
|
||
* 地面(カウンター) : 北が半分侵入可書き割り、■通行不可
|
||
* [A2 右側][×][♢][UseLayeredCounter:ON]
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setCounterPass(flags, tileId) {
|
||
const COUNTER_PASS = [
|
||
15, 15, 15, 15, 15, 15, 15, 15,
|
||
15, 15, 15, 15, 15, 15, 15, 15,
|
||
15, 15, 15, 15, 28, 28, 28, 28,
|
||
15, 15, 15, 15, 15, 15, 15, 15,
|
||
15, 28, 28, 28, 28, 28, 15, 15,
|
||
15, 15, 28, 28, 15, 28, 28, 28,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_DIR_UPPER | FLAG_COUNTER, COUNTER_PASS);
|
||
}
|
||
/**
|
||
* 中空の地形に変更。
|
||
* [A2][×][IsA2FullCollision:OFF] □周囲=通行不可
|
||
* [A4][○][♢][TT] □周囲=通行不可
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setEmptyLinePass(flags, tileId) {
|
||
const EMPTY_PASS = [
|
||
0, 0, 0, 0, 0, 0, 0, 0,
|
||
0, 0, 0, 0, 0, 0, 0, 0,
|
||
2, 2, 2, 2, 8, 8, 8, 8,
|
||
4, 4, 4, 4, 1, 1, 1, 1,
|
||
6, 9, 10, 10, 12, 12, 5, 5,
|
||
3, 3, 14, 11, 7, 13, 15, 15
|
||
];
|
||
//if( isCrossPass ) EMPTY_PASS.map( v => OPTT + v );
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_DIR_UPPER, EMPTY_PASS);
|
||
};
|
||
/**
|
||
* 屋根 : 北が立体交差、他は周囲通行不可に変更。
|
||
* [A3 奇数列][×][♢][TT]
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setA3UpperOverPass(flags, tileId) {
|
||
const A3_UPPER_OVERPASS = TF_IsA3UpperOpen ? [
|
||
0, 2, OPTT + 8, OPTT + 10,
|
||
4, 6, OPTT + 12, OPTT + 14,
|
||
0, 2, OPTT + 8, OPTT + 10,
|
||
4, 6, OPTT + 12, OPTT + 14,
|
||
] : [
|
||
0, 2, OPTT + 8, OPTT + 10,
|
||
4, 6, OPTT + 12, OPTT + 14,
|
||
1, 3, OPTT + 9, OPTT + 11,
|
||
5, 7, OPTT + 15, OPTT + 13,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_TAG_DIR_UPPER, A3_UPPER_OVERPASS);
|
||
}
|
||
/**
|
||
* 屋根 : 北が書き割り、他は周囲通行不可に変更。
|
||
* [A3 奇数列][×][カウンター]
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setRoofUpperPass(flags, tileId) {
|
||
const A3_UPPER_PASS = TF_IsA3UpperOpen ? [
|
||
0, 2, 17, 17,
|
||
4, 6, 17, 17,
|
||
0, 2, 17, 17,
|
||
4, 6, 17, 17,
|
||
] : [
|
||
0, 2, 17, 17,
|
||
4, 6, 17, 17,
|
||
1, 3, 17, 17,
|
||
5, 7, 17, 17,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_DIR_UPPER, A3_UPPER_PASS);
|
||
}
|
||
/**
|
||
* 壁(上面) : 北が立体交差、他は周囲通行不可に変更。
|
||
* [A4 奇数列][×][カウンター][OverpassTerrainTag]
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setA4UpperOverPass(flags, tileId) {
|
||
const A4_UPPER_OVERPASS = TF_IsA4UpperOpen ? [
|
||
0, 0, 0, 0, 0, 0, 0, 0,
|
||
0, 0, 0, 0, 0, 0, 0, 0,
|
||
2, 2, 2, 2, OPTT + 8, OPTT + 8, OPTT + 8, OPTT + 8,
|
||
4, 4, 4, 4, 0, 0, 0, 0,
|
||
6, OPTT + 8, OPTT + 10, OPTT + 10, OPTT + 12, OPTT + 12, 4, 4,
|
||
2, 2, OPTT + 14, OPTT + 10, 6, OPTT + 12, OPTT + 14, OPTT + 15,
|
||
] : [
|
||
0, 0, 0, 0, 0, 0, 0, 0,
|
||
0, 0, 0, 0, 0, 0, 0, 0,
|
||
2, 2, 2, 2, OPTT + 8, OPTT + 8, OPTT + 8, OPTT + 8,
|
||
4, 4, 4, 4, 1, 1, 1, 1,
|
||
6, OPTT + 9, OPTT + 10, OPTT + 10, OPTT + 12, OPTT + 12, 5, 5,
|
||
3, 3, OPTT + 14, OPTT + 11, 7, OPTT + 13, OPTT + 15, OPTT + 15,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_TAG_DIR_UPPER, A4_UPPER_OVERPASS);
|
||
}
|
||
/**
|
||
* 壁(上面) : 北が書き割り、他は周囲通行不可に変更。
|
||
* [A4 奇数列][×][カウンター]
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setA4UpperPass(flags, tileId) {
|
||
const A4_UPPER_PASS = TF_IsA4UpperOpen ? [
|
||
0, 2, 4, 6, 0, 2, 4, 6,
|
||
0, 2, 4, 6, 0, 2, 4, 6,
|
||
2, 6, 2, 6, 17, 17, 17, 17,
|
||
4, 4, 6, 6, 0, 2, 4, 6,
|
||
6, 17, 17, 17, 17, 17, 4, 6,
|
||
2, 6, 17, 17, 6, 17, 17, 17,
|
||
] : [
|
||
0, 2, 4, 6, 0, 2, 4, 6,
|
||
0, 2, 4, 6, 0, 2, 4, 6,
|
||
2, 6, 2, 6, 17, 17, 17, 17,
|
||
4, 4, 6, 6, 1, 3, 5, 7,
|
||
6, 17, 17, 17, 17, 17, 5, 7,
|
||
3, 7, 17, 17, 7, 17, 17, 17,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_DIR_UPPER, A4_UPPER_PASS);
|
||
}
|
||
/**
|
||
* 壁(上面) : 北が☆、他は通行不可に変更。
|
||
* [A4 奇数列][○][TT]
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setA4UpperStarPass(flags, tileId) {
|
||
const A4_UPPER_STAR_PASS = [
|
||
15, 15, 15, 15, 15, 15, 15, 15,
|
||
15, 15, 15, 15, 15, 15, 15, 15,
|
||
15, 15, 15, 15, 16, 16, 16, 16,
|
||
15, 15, 15, 15, 15, 15, 15, 15,
|
||
15, 16, 16, 16, 16, 16, 15, 15,
|
||
15, 15, 16, 16, 15, 16, 16, 16,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_TAG_DIR_UPPER, A4_UPPER_STAR_PASS);
|
||
}
|
||
/**
|
||
* 壁(側面):南が書き割り、他は通行可に変更。
|
||
* [A3・A4 偶数列][○]
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setWallSideEdgePass(flags, tileId) {
|
||
const WALL_SIDE_PASS_EDGE = [
|
||
15, 15, 17, 17,
|
||
15, 15, 17, 17,
|
||
15, 15, 17, 17,
|
||
15, 15, 17, 17,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_DIR_UPPER, WALL_SIDE_PASS_EDGE);
|
||
}
|
||
/**
|
||
* 壁(側面): 北が書き割り、他は全通行不可に変更。
|
||
* [A3・A4 偶数列][○][♢]
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setWallSidePass(flags, tileId) {
|
||
const WALL_SIDE_PASS = [
|
||
25, 25, 26, 26,
|
||
25, 25, 26, 26,
|
||
17, 17, 17, 17,
|
||
17, 17, 17, 17,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_DIR_UPPER, WALL_SIDE_PASS);
|
||
}
|
||
/**
|
||
* 屋根 (地面) : 周囲通行不可に変更。
|
||
* [A3 奇数列][×]
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setRoofBottomPass(flags, tileId) {
|
||
if (TF_IsA3UpperOpen) {
|
||
setSquareOpenPass(flags, tileId);
|
||
} else {
|
||
setEmptySquarePass(flags, tileId);
|
||
}
|
||
}
|
||
/**
|
||
* 屋根 (地面) : 南以外通行不可に変更。
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setSquareOpenPass(flags, tileId) {
|
||
const SQUARE_PASS = [
|
||
0, 2, 8, 10,
|
||
4, 6, 12, 14,
|
||
0, 2, 8, 10,
|
||
4, 6, 12, 14,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_DIR_UPPER, SQUARE_PASS);
|
||
}
|
||
/**
|
||
* 屋根 (地面) : 全周通行不可に変更。
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setEmptySquarePass(flags, tileId) {
|
||
const SQUARE_PASS = [
|
||
0, 2, 8, 10,
|
||
4, 6, 12, 14,
|
||
1, 3, 9, 11,
|
||
5, 7, 13, 15,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_DIR_UPPER, SQUARE_PASS);
|
||
}
|
||
/**
|
||
* 南北の橋設定に変更。
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
* @param {Boolean} isCrossPass 立体交差か
|
||
*/
|
||
function setBridgeSNPass(flags, tileId, isCrossPass) {
|
||
const BRIDGE_SN_PASS = isCrossPass ? [
|
||
OPTT + 0, OPTT + 2, OPTT + 0, OPTT + 2,
|
||
OPTT + 4, OPTT + 6, OPTT + 4, OPTT + 6,
|
||
OPTT + 0, OPTT + 2, OPTT + 0, OPTT + 2,
|
||
OPTT + 4, OPTT + 6, OPTT + 4, OPTT + 6,
|
||
] : [
|
||
0, 2, 0, 2,
|
||
4, 6, 4, 6,
|
||
0, 2, 0, 2,
|
||
4, 6, 4, 6,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_TAG_DIR_UPPER, BRIDGE_SN_PASS);
|
||
}
|
||
/**
|
||
* 東西の橋設定に変更。
|
||
* @param {Array<Number>} flags 地形フラグの配列
|
||
* @param {Number} tileId タイルID
|
||
* @param {Boolean} isCrossPass 立体交差か
|
||
*/
|
||
function setBridgeWEPass(flags, tileId, isCrossPass) {
|
||
const BRIDGE_WE_PASS = isCrossPass ? [
|
||
OPTT + 0, OPTT + 0, OPTT + 8, OPTT + 8,
|
||
OPTT + 0, OPTT + 0, OPTT + 8, OPTT + 8,
|
||
OPTT + 1, OPTT + 1, OPTT + 9, OPTT + 9,
|
||
OPTT + 1, OPTT + 1, OPTT + 9, OPTT + 9,
|
||
] : [
|
||
0, 0, 8, 8,
|
||
0, 0, 8, 8,
|
||
1, 1, 9, 9,
|
||
1, 1, 9, 9,
|
||
];
|
||
replaceCollision(flags, tileId, MASK_WITHOUT_TAG_DIR_UPPER, BRIDGE_WE_PASS);
|
||
}
|
||
|
||
|
||
|
||
/*---- Scene_Map ---*/
|
||
/**
|
||
* シーン表示前に、マップデータを書き換える。
|
||
*/
|
||
const _Scene_Map_onMapLoaded = Scene_Map.prototype.onMapLoaded;
|
||
Scene_Map.prototype.onMapLoaded = function () {
|
||
if (this._transfer) $gamePlayer.performTransfer(); // シーン遷移時のマップデータ置き換え処理
|
||
treatDataMap();
|
||
_Scene_Map_onMapLoaded.call(this);
|
||
|
||
/**
|
||
* カウンター設定のA3・A4オートタイルの箇所に、低層の補完タイルを設定。
|
||
*/
|
||
function treatDataMap() {
|
||
const flags = $gameMap.tilesetFlags();
|
||
for (let y = 0; y < $dataMap.height; y++) {
|
||
for (let x = 0; x < $dataMap.width; x++) {
|
||
const tileId = getMapData(x, y, 0);
|
||
|
||
// 対象タイルを上層へ
|
||
if (Tilemap.isTileA5(tileId) && isOverpassTile(flags[tileId])) {
|
||
setMapData(x, y, 1, tileId);
|
||
} else if (isA3A4Tile(tileId)) {
|
||
if (isOverpassTile(flags[tileId])) {
|
||
setMapData(x, y, 2, tileId);
|
||
} else if (!isFullCollisionTile(flags[tileId]) && isCollisionTile(flags[tileId])) {
|
||
setMapData(x, y, 1, tileId);
|
||
} else continue; // 衝突判定が完全に[○]か[×]のタイルは通常処理(A2右タイルを上に置ける)
|
||
} else continue;
|
||
|
||
|
||
if (TF_FillWithNeighborTile) {
|
||
// 北タイルで補完ただし、一番南は南で補完
|
||
const southTileId = getMapData(x, $gameMap.roundY(y + 1), 0);
|
||
if (isA3A4Tile(southTileId) || Tilemap.isTileA5(southTileId) && isOverpassTile(flags[southTileId])) {
|
||
const northTileId = getMapData(x, $gameMap.roundY(y - 1), 0);
|
||
setMapData(x, y, 0, northTileId ? northTileId : TF_DefaultLowerTileId);
|
||
} else {
|
||
setMapData(x, y, 0, southTileId ? southTileId : TF_DefaultLowerTileId);
|
||
}
|
||
} else {
|
||
// 指定タイルで補完
|
||
setMapData(x, y, 0, TF_DefaultLowerTileId);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* A3・A4タイルか。
|
||
* @param {Number} tileId タイルID
|
||
* @returns {Boolean}
|
||
*/
|
||
function isA3A4Tile(tileId) {
|
||
return (Tilemap.isTileA3(tileId) || Tilemap.isTileA4(tileId));
|
||
}
|
||
/**
|
||
* 指定位置のタイルIDを返す。
|
||
* @param {Number} x x座標(タイル数)
|
||
* @param {Number} y y座標(タイル数)
|
||
* @param {*} z レイヤー位置
|
||
* @returns {Number} タイルID
|
||
*/
|
||
function getMapData(x, y, z) {
|
||
return $dataMap.data[x + ($gameMap.roundY(y) + z * $dataMap.height) * $dataMap.width];
|
||
}
|
||
/**
|
||
* マップデータにタイルIDを書き込む。
|
||
* @param {Number} x x座標(タイル数)
|
||
* @param {Number} y y座標(タイル数)
|
||
* @param {Number} z レイヤー位置
|
||
* @param {Number} tileId タイルID
|
||
*/
|
||
function setMapData(x, y, z, tileId) {
|
||
$dataMap.data[x + ($gameMap.roundY(y) + z * $dataMap.height) * $dataMap.width] = tileId;
|
||
}
|
||
|
||
}
|
||
};
|
||
|
||
|
||
/*---- Game_CharacterBase ----*/
|
||
/**
|
||
* レイヤー位置を返す。
|
||
* @returns {Number} レイヤー位置(立体交差上5、その他3)
|
||
*/
|
||
const _Game_CharacterBase_screenZ = Game_CharacterBase.prototype.screenZ;
|
||
Game_CharacterBase.prototype.screenZ = function () {
|
||
return this._higherLevel ? 5 : _Game_CharacterBase_screenZ.call(this);
|
||
};
|
||
|
||
/**
|
||
* 指定座標がイベントで塞がれているか。高さレベルを考慮する。
|
||
* TODO : HalfMove.js とコンフリクトするので、回避方法を探る
|
||
* @param {Number} x タイル数
|
||
* @param {Number} y タイル数
|
||
* @returns {Boolean}
|
||
*/
|
||
//const _Game_CharacterBase_isCollidedWithEvents = Game_CharacterBase.prototype.isCollidedWithEvents;
|
||
// Game_CharacterBase.prototype.isCollidedWithEvents = function( x, y ){
|
||
// const events = $gameMap.eventsXyNt( x, y );
|
||
// return events.some( event => Boolean( this._higherLevel ) === Boolean( event._higherLevel ) );
|
||
// };
|
||
|
||
/**
|
||
* 指定方向への移動が可能か
|
||
* キャラクタ半分の位置が関係するものは、ここで判定。
|
||
* @param {Number} halfX タイル数(0.5刻み)
|
||
* @param {Number} halfY タイル数(0.5刻み)
|
||
* @param {Number} d 向き(テンキー対応)
|
||
* @returns {Boolean} 移動可能か
|
||
*/
|
||
const _Game_CharacterBase_isMapPassable = Game_CharacterBase.prototype.isMapPassable;
|
||
Game_CharacterBase.prototype.isMapPassable = function (halfX, halfY, d) {
|
||
const x = Math.floor(halfX + 0.5);
|
||
const y = Math.floor(halfY + 0.5);
|
||
const halfPos = getHalfPos(halfX, halfY);
|
||
const dx = getDx(d);
|
||
// const dy =getDy( d );
|
||
const rd = this.reverseDir(d);
|
||
const flags = $gameMap.tilesetFlags();
|
||
|
||
/**
|
||
* 指定位置に指定flagがあるか
|
||
* @param {Number} x タイル数
|
||
* @param {Number} y タイル数
|
||
* @param {Number} collisionType 調べるタイルのflag(高層[☆]と通行)
|
||
* @returns {Boolean}
|
||
*/
|
||
const checkCollision = (x, y, collisionType) => {
|
||
const tiles = $gameMap.allTiles(Math.floor(x), Math.floor(y));
|
||
|
||
for (let i = 0; i < tiles.length; i++) {
|
||
if ((flags[tiles[i]] & MASK_UPPER_DIR) === collisionType) return true;
|
||
}
|
||
return false;
|
||
};
|
||
|
||
const isFurniturePassable = () => {
|
||
// FLOOR1_N_FULL
|
||
if (d === 2) {
|
||
if ((halfPos === 2 || halfPos === 3) && checkCollision(x, y + 1, FLOOR1_N_FULL)) return false;
|
||
if (halfPos === 2 && checkCollision(x - 1, y + 1, FLOOR1_N_FULL)) return false;
|
||
} else if (d === 8) {
|
||
if ((halfPos === 2 || halfPos === 3) && checkCollision(x, y, FLOOR1_N_FULL)) return false;
|
||
if ((halfPos === 2) && checkCollision(x - 1, y, FLOOR1_N_FULL)) return false;
|
||
} else if (d === 4 || d === 6) {
|
||
if (halfPos === 1 && checkCollision(x + dx, y, FLOOR1_N_FULL)) return false;
|
||
}
|
||
|
||
//FLOOR1_S_FULL
|
||
if (d === 2) {
|
||
if ((halfPos === 0 || halfPos === 1) && checkCollision(x, y, FLOOR1_S_FULL)) return false;
|
||
if (halfPos === 0 && checkCollision(x - 1, y, FLOOR1_S_FULL)) return false;
|
||
} else if (d === 8) {
|
||
if ((halfPos === 0 || halfPos === 1) && checkCollision(x, y - 1, FLOOR1_S_FULL)) return false;
|
||
if (halfPos === 0 && checkCollision(x - 1, y - 1, FLOOR1_S_FULL)) return false;
|
||
} else if (d === 4 || d === 6) {
|
||
if (halfPos === 3 && checkCollision(x + dx, y, FLOOR1_S_FULL)) return false;
|
||
}
|
||
|
||
// FLOOR1_N_HALF
|
||
if (d === 2) {
|
||
if (halfPos === 3 && checkCollision(x, y + 1, FLOOR1_N_HALF)) return false;
|
||
} else if (d === 8) {
|
||
if (halfPos === 3 && checkCollision(x, y, FLOOR1_N_HALF)) return false;
|
||
} else if (d === 4) {
|
||
if (halfPos === 0 && checkCollision(x - 1, y, FLOOR1_N_HALF)) return false;
|
||
} else if (d === 6) {
|
||
if (halfPos === 0 && checkCollision(x, y, FLOOR1_N_HALF)) return false;
|
||
}
|
||
|
||
// FLOOR1_S_HALF
|
||
if (d === 2) {
|
||
if (halfPos === 1 && checkCollision(x, y, FLOOR1_S_HALF)) return false;
|
||
} else if (d === 8) {
|
||
if (halfPos === 1 && checkCollision(x, y - 1, FLOOR1_S_HALF)) return false;
|
||
} else if (d === 4) {
|
||
if (halfPos === 2 && checkCollision(x - 1, y, FLOOR1_S_HALF)) return false;
|
||
} else if (d === 6) {
|
||
if (halfPos === 2 && checkCollision(x, y, FLOOR1_S_HALF)) return false;
|
||
}
|
||
|
||
// FLOOR1_S_FLAT
|
||
if (d === 2) {
|
||
if (halfPos === 3 && checkCollision(x, y, FLOOR1_S_FLAT)) return false;
|
||
} else if (d === 8) {
|
||
if (halfPos === 1 && checkCollision(x, y - 1, FLOOR1_S_FLAT)) return false;
|
||
}
|
||
|
||
return null;
|
||
};
|
||
|
||
// Overpass タグが設定されていない
|
||
if (TF_OverpassTerrainTag === 0) {
|
||
const isFPassable = isFurniturePassable();
|
||
if (isFPassable !== null) return isFPassable;
|
||
return _Game_CharacterBase_isMapPassable.apply(this, arguments);
|
||
}
|
||
|
||
|
||
/*---- Overpass 用のプログラム ----*/
|
||
|
||
// 立体交差の下では、家具の衝突判定は行わない
|
||
if (this._higherLevel || (!this._higherLevel && !isOverpassTileAt(x, y))) {
|
||
const isFPassable = isFurniturePassable();
|
||
if (isFPassable !== null) return isFPassable;
|
||
}
|
||
|
||
const isOverpassMapPassable = () => {
|
||
if (isOverpassTileAt(x, y)) {
|
||
// 下を潜っている状態は端の通行判定を逆転
|
||
if (d === 2) {
|
||
if ((halfPos === 2 || halfPos === 3) &&
|
||
!isOverpassTileAt(x, y + 1) && checkOverpassCollision(x, y, 2) === false
|
||
) return false;
|
||
} else if (d === 8) {
|
||
if (halfPos === 2 || halfPos === 3) {
|
||
if (TF_CharacterSize === 2) {
|
||
if (!isOverpassTileAt(x, y - 2) && checkOverpassCollision(x, y - 1, 8) === false) return false;
|
||
} else if (!isOverpassTileAt(x, y - 1) && checkOverpassCollision(x, y, 8) === false) return false;
|
||
}
|
||
} else if (d === 4 || d === 6) {
|
||
if ((halfPos === 1 || halfPos === 3) &&
|
||
!isOverpassTileAt(x + dx, y) && checkOverpassCollision(x, y, d) === false
|
||
) return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 東の境界
|
||
if (isOverpassTileAt(x - 1, y)) {
|
||
if (halfPos === 0) return true;
|
||
if (halfPos === 2) {
|
||
if (d === 2) {
|
||
if (!isOverpassTileAt(x - 1, y + 1) && checkOverpassCollision(x - 1, y, 2) === false) return false;
|
||
} else if (d === 8) {
|
||
if (TF_CharacterSize === 2) {
|
||
if (!isOverpassTileAt(x - 1, y - 2) && checkOverpassCollision(x - 1, y - 1, 8) === false) return false;
|
||
} else if (!isOverpassTileAt(x - 1, y - 1) && checkOverpassCollision(x - 1, y, 8) === false) return false;
|
||
}
|
||
return true;
|
||
}
|
||
} else if (d === 8 && halfPos === 0 && checkOverpassCollisionBit(x - 1, y - 1, 5)) return true; // 東の角┘
|
||
|
||
// 潜る
|
||
if (d === 2) {
|
||
if (halfPos === 2) {
|
||
if (checkOverpassCollisionBit(x - 1, y + 1, 12)) return true; // 東の角┐
|
||
if (checkOverpassCollisionBit(x, y + 1, 9)) return true; // 西の角┌
|
||
if (checkOverpassCollision(x, y + 1, 8)) {
|
||
if (checkOverpassCollision(x - 1, y + 1, 8)) return true;
|
||
}
|
||
} else if (halfPos === 3) {
|
||
if (checkOverpassCollision(x, y + 1, 8)) return true;
|
||
}
|
||
} else if (d === 8) {
|
||
if (halfPos === 0) {
|
||
if (checkOverpassCollisionBit(x, y - 1, 3)) return true; // 西の角└
|
||
if (checkOverpassCollision(x, y - 1, 2) && checkOverpassCollision(x - 1, y - 1, 2)) return true;
|
||
} else if (halfPos === 1) {
|
||
if (checkOverpassCollision(x, y - 1, 2)) return true;
|
||
}
|
||
} else if (d === 4 || d === 6) {
|
||
if (checkOverpassCollision(x + dx, y, rd)) {
|
||
if (checkOverpassCollision(x + dx, y - 1, rd)) {
|
||
if (halfPos === 3) return true;
|
||
if (halfPos === 1 && TF_CharacterSize === 1 || checkOverpassCollision(x + dx, y - 2, rd)) return true;
|
||
}
|
||
if ((halfPos === 1 || halfPos === 3) && checkOverpassCollision(x + dx, y, 8)) return true; // ┌西東┐の角
|
||
}
|
||
}
|
||
|
||
|
||
// 境界の北の衝突判定
|
||
if (d === 2) {
|
||
if (halfPos === 0 && !isOverpassTileAt(x, y) && !isOverpassTileAt(x - 1, y)) {
|
||
if (!isOverpassTileAt(x - 1, y + 1) &&
|
||
checkOverpassCollision(x, y + 1, 4) === false &&
|
||
checkOverpassCollision(x, y + 1, 2)) return false;
|
||
if (!isOverpassTileAt(x, y + 1) &&
|
||
checkOverpassCollision(x - 1, y + 1, 6) === false &&
|
||
checkOverpassCollision(x - 1, y + 1, 2)) return false;
|
||
}
|
||
} else if (d === 4 || d === 6) {
|
||
if (halfPos === 3 && !isOverpassTileAt(x + dx, y)) {
|
||
if (!isOverpassTileAt(x + dx, y + 1) &&
|
||
checkOverpassCollision(x, y + 1, d) === false &&
|
||
checkOverpassCollision(x, y + 1, 8)) return false;
|
||
if (!isOverpassTileAt(x, y + 1) &&
|
||
checkOverpassCollision(x + dx, y + 1, rd) === false &&
|
||
checkOverpassCollision(x + dx, y + 1, 8)) return false;
|
||
}
|
||
}
|
||
|
||
// 境界の南の衝突判定
|
||
if (halfPos === 1 || (TF_CharacterSize === 2 && halfPos === 3)) {
|
||
if ((d === 4 || d === 6) && !isOverpassTileAt(x + dx, y)) {
|
||
if (!isOverpassTileAt(x + dx, y - 1) &&
|
||
checkOverpassCollision(x, y - 1, d) === false &&
|
||
checkOverpassCollision(x, y - 1, 2)) return false;
|
||
if (!isOverpassTileAt(x, y - 1) &&
|
||
checkOverpassCollision(x + dx, y - 1, rd) === false &&
|
||
checkOverpassCollision(x + dx, y - 1, 2)) return false;
|
||
}
|
||
} else if (d === 8) {
|
||
if (TF_CharacterSize === 2) {
|
||
if (halfPos === 0 && !isOverpassTileAt(x, y - 1) && !isOverpassTileAt(x - 1, y - 1)) {
|
||
if (!isOverpassTileAt(x - 1, y - 2) &&
|
||
checkOverpassCollision(x, y - 2, 4) === false &&
|
||
checkOverpassCollision(x, y - 2, 2)) return false;
|
||
if (!isOverpassTileAt(x, y - 2) &&
|
||
checkOverpassCollision(x - 1, y - 2, 6) === false &&
|
||
checkOverpassCollision(x - 1, y - 2, 2)) return false;
|
||
}
|
||
} else if (halfPos === 2 && !isOverpassTileAt(x, y) && !isOverpassTileAt(x - 1, y)) {
|
||
if (!isOverpassTileAt(x - 1, y - 1) &&
|
||
checkOverpassCollision(x, y - 1, 4) === false &&
|
||
checkOverpassCollision(x, y - 1, 2)) return false;
|
||
if (!isOverpassTileAt(x, y - 1) &&
|
||
checkOverpassCollision(x - 1, y - 1, 6) === false &&
|
||
checkOverpassCollision(x - 1, y - 1, 2)) return false;
|
||
}
|
||
}
|
||
return null;
|
||
};
|
||
|
||
// 乗る
|
||
const isGateway = isUp2Higher(x, y, d, halfPos);
|
||
if (isGateway) this._higherLevel = true;
|
||
|
||
if (this._higherLevel) {
|
||
if (isDownFromUpperTile(x, y, d, halfPos)) this._higherLevel = false;
|
||
return _Game_CharacterBase_isMapPassable.apply(this, arguments);
|
||
}
|
||
|
||
const isOPMapPassable = isOverpassMapPassable();
|
||
if (isOPMapPassable === null) return _Game_CharacterBase_isMapPassable.apply(this, arguments);
|
||
if (isOPMapPassable === false) return false;
|
||
|
||
const checkUnderpassCollision = (x, y, d) => {
|
||
const x2 = $gameMap.roundX(x + getDx(d));
|
||
const y2 = $gameMap.roundY(y + getDy(d));
|
||
if (isOverpassTileAt(x2, y2)) {
|
||
if (isGateway) return true;
|
||
if ((flags[$gameMap.tileId(x, y, 0)] |
|
||
flags[$gameMap.tileId(x, y, 1)]) &
|
||
getFlag(d)
|
||
) return false;
|
||
if ((flags[$gameMap.tileId(x2, y2, 0)] |
|
||
flags[$gameMap.tileId(x2, y2, 1)]) &
|
||
getFlag(rd)
|
||
) return false;
|
||
}
|
||
return true;
|
||
};
|
||
|
||
// レイヤー0,1の衝突判定
|
||
if (!this._higherLevel &&
|
||
((halfPos === 1 || halfPos === 3) && (d === 4 || d === 6)) ||
|
||
((halfPos === 0 || halfPos === 1) && d === 8) ||
|
||
((halfPos === 2 || halfPos === 3) && d === 2)
|
||
) {
|
||
if (checkUnderpassCollision(x, y, d)) {
|
||
if ((halfPos === 0 && d === 8) || (halfPos === 2 && d === 2)) {
|
||
if (!checkUnderpassCollision(x - 1, y, d)) return false;
|
||
}
|
||
} else return false;
|
||
}
|
||
|
||
return isOPMapPassable;
|
||
};
|
||
|
||
/*---- Game_Follower ----*/
|
||
/**
|
||
* 指定位置の指定フラグビットが通行可か。
|
||
* @param {Number} character 追うキャラクタ
|
||
*/
|
||
const _Game_Follower_chaseCharacter = Game_Follower.prototype.chaseCharacter;
|
||
Game_Follower.prototype.chaseCharacter = function (character) {
|
||
if (TF_OverpassTerrainTag === 0) {
|
||
_Game_Follower_chaseCharacter.apply(this, arguments);
|
||
return;
|
||
}
|
||
|
||
const sx = this.deltaXFrom(character.x);
|
||
const sy = this.deltaYFrom(character.y);
|
||
const d = 5 - Math.sign(sx) + ((sx === 0) ? Math.sign(sy) * 3 : 0);
|
||
if (d === 5) {
|
||
_Game_Follower_chaseCharacter.apply(this, arguments);
|
||
return;
|
||
}
|
||
|
||
const x = Math.floor(this.x + 0.5);
|
||
const y = Math.floor(this.y + 0.5);
|
||
const halfPos = getHalfPos(this.x, this.x);
|
||
if (this._higherLevel) {
|
||
if (isDownFromUpperTile(x, y, d, halfPos)) this._higherLevel = false;
|
||
} else {
|
||
if (isUp2Higher(x, y, d, halfPos)) this._higherLevel = true;
|
||
}
|
||
|
||
_Game_Follower_chaseCharacter.apply(this, arguments);
|
||
};
|
||
|
||
|
||
/*---- Game_Event ----*/
|
||
var _Game_Event_initialize = Game_Event.prototype.initialize;
|
||
Game_Event.prototype.initialize = function (mapId, eventId) {
|
||
_Game_Event_initialize.apply(this, arguments);
|
||
|
||
const getMetaValue = (object, name) => {
|
||
const metaTagName = 'TF_' + name;
|
||
return object.meta.hasOwnProperty(metaTagName) ? object.meta[metaTagName] : undefined;
|
||
};
|
||
|
||
const zDef = getMetaValue(this.event(), 'zDef');
|
||
if (zDef !== undefined) this._TF_zDef = parseFloat(zDef);
|
||
|
||
const higherLevel = getMetaValue(this.event(), 'higherLevel');
|
||
if (higherLevel !== undefined) this._higherLevel = (higherLevel.toLowerCase() === PARAM_TRUE);
|
||
};
|
||
|
||
|
||
/*---- Game_Map ----*/
|
||
/**
|
||
* 指定位置の指定フラグビットが通行可か。
|
||
* @param {Number} x タイル数
|
||
* @param {Number} y タイル数
|
||
* @param {Number} bit {@link RPG.Tileset}の flagsチェック用ビット
|
||
* @returns {Boolean} 高層表示[☆]の4方向の通行設定については@helpを参照
|
||
*/
|
||
//const _Game_Map_checkPassage = Game_Map.prototype.checkPassage;
|
||
Game_Map.prototype.checkPassage = function (x, y, bit) {
|
||
const flags = this.tilesetFlags();
|
||
const tiles = this.allTiles(x, y);
|
||
const isOverpass = isOverpassTileAt(x, y);
|
||
const lastIndex = tiles.length - (($gamePlayer._higherLevel && isOverpass) ? 2 : 0);
|
||
for (let i = 0; i < lastIndex; i++) {
|
||
const tileId = tiles[i];
|
||
const flag = flags[tileId];
|
||
|
||
if (tileId === 0 || // Bタイルの左上は無視
|
||
(flag & FLAG_UPPER) && ( // [☆]かつ
|
||
(flag & FLAG_NORTH_DIR) || // ・北通行不可タイルは無視
|
||
!(flag & MASK_ALL_DIR) // ・全通行可タイルは無視
|
||
)
|
||
) continue;
|
||
if ((flag & bit) === 0) return true;
|
||
if ((flag & bit) === bit) return false;
|
||
}
|
||
return $gamePlayer._higherLevel && isOverpass;
|
||
//return _Game_Map_checkPassage.apply( this, arguments );
|
||
};
|
||
|
||
|
||
/**
|
||
* 指定位置の立体交差地形タグを持つタイルの通行判定(4方向)チェック
|
||
* @param {Number} ax タイル数
|
||
* @param {Number} ay タイル数
|
||
* @param {Number} d 通行設定(テンキー方向)
|
||
* @returns {Boolean} 立体交差タイルでない場合nullを返す
|
||
*/
|
||
function checkOverpassCollision(x, y, d) {
|
||
return checkOverpassCollisionBit(x, y, getFlag(d));
|
||
}
|
||
|
||
/**
|
||
* 指定位置の立体交差地形タグを持つタイルの通行判定(ビットフラグ)チェック
|
||
* @param {Number} ax タイル数
|
||
* @param {Number} ay タイル数
|
||
* @param {Number} bit 通行設定(ビットフラグ)
|
||
* @returns {Boolean} 立体交差タイルでない場合nullを返す
|
||
*/
|
||
function checkOverpassCollisionBit(x, y, bit) {
|
||
const flags = $gameMap.tilesetFlags();
|
||
const tiles = $gameMap.allTiles(Math.floor($gameMap.roundX(x)), Math.floor($gameMap.roundY(y)));
|
||
|
||
for (let i = 0; i < tiles.length; i++) {
|
||
const flag = flags[tiles[i]];
|
||
if (flag >> 12 === TF_OverpassTerrainTag && !Tilemap.isTileA5(tiles[i])) {
|
||
return (flag & bit) === bit;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 指定位置のタイルは立体交差地形タグを持つか
|
||
* @param {Number} x タイル数
|
||
* @param {Number} y タイル数
|
||
* @returns {Boolean} 立体交差タイルでない場合nullを返す
|
||
*/
|
||
function isOverpassTileAt(x, y) {
|
||
const flags = $gameMap.tilesetFlags();
|
||
const tiles = $gameMap.layeredTiles($gameMap.roundX(x), $gameMap.roundY(y));
|
||
for (let i = 0; i < tiles.length; i++) {
|
||
if (flags[tiles[i]] >> 12 === TF_OverpassTerrainTag && !Tilemap.isTileA5(tiles[i])) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
/**
|
||
* 高層へ上がるタイミングか
|
||
* @param {Number} x タイル数
|
||
* @param {Number} y タイル数
|
||
* @param {Number} d 通行設定(テンキー方向)
|
||
* @param {Number} halfPos タイル内での位置
|
||
* @returns {Boolean}
|
||
*/
|
||
function isUp2Higher(x, y, d, halfPos) {
|
||
if (halfPos === 0 || halfPos === 2) {
|
||
if (!isOverpassTileAt(x - 1, y) && checkOverpassCollision(x, y, 4) === false) return true; // 西出入口境界
|
||
}
|
||
if (isOverpassTileAt(x, y)) return false; // 立体交差タイルの上は帰す
|
||
|
||
return (
|
||
checkOverpassCollision(x - 1, y, 6) === false || // 東出入口
|
||
checkOverpassCollision(x + 1, y, 4) === false || // 西出入口
|
||
checkOverpassCollision(x, y + 1, 8) === false || // 北入り口↓
|
||
(!isOverpassTileAt(x - 1, y) && checkOverpassCollision(x - 1, y + 1, 8) === false) ||
|
||
(!isOverpassTileAt(x, y - 1) && checkOverpassCollision(x, y - 2, 2) === false) || // 南入口↓
|
||
(!isOverpassTileAt(x - 1, y) && (checkOverpassCollision(x - 1, y - 1, 2) === false ||
|
||
(!isOverpassTileAt(x - 1, y - 1) && checkOverpassCollision(x - 1, y - 2, 2) === false))
|
||
) ||
|
||
(!isOverpassTileAt(x + 1, y) && checkOverpassCollision(x + 1, y - 1, 2) === false)
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 高層から降りるタイミングか
|
||
* @param {Number} x タイル数
|
||
* @param {Number} y タイル数
|
||
* @param {Number} d 通行設定(テンキー方向)
|
||
* @param {Number} halfPos タイル内での位置
|
||
* @returns {Boolean}
|
||
*/
|
||
function isDownFromUpperTile(x, y, d, halfPos) {
|
||
if (isOverpassTileAt(x, y)) return false; // 立体交差タイルの上は帰す
|
||
if (checkOverpassCollision(x, y - 1, 2) === false) return false; // 南入り口タイルは帰す
|
||
if ((halfPos === 0 || halfPos === 2) && checkOverpassCollision(x - 1, y - 1, 2) === false) return false;
|
||
|
||
// 全周に立体交差タイルの入り口がない
|
||
return checkOverpassCollision(x + 1, y, 4) !== false && // 東
|
||
checkOverpassCollision(x - 1, y, 6) !== false && // 西
|
||
checkOverpassCollision(x, y + 1, 8) !== false && // 南
|
||
checkOverpassCollision(x - 1, y + 1, 8) !== false && // 南西
|
||
checkOverpassCollision(x, y - 2, 2) !== false; // ふたつ北
|
||
}
|
||
|
||
/**
|
||
* タイル内の位置を返す( 0:左上, 1:上, 2:左下, 3:下 )
|
||
* @param {Number} x x座標(タイル数)
|
||
* @param {Number} y y座標(タイル数)
|
||
*/
|
||
function getHalfPos(x, y) {
|
||
return (((x % 1) === 0) ? 1 : 0) + (((y % 1) === 0) ? 2 : 0);
|
||
}
|
||
/**
|
||
* 指定方向のX要素を返す。
|
||
* @param {Number} d 方向(テンキー対応)
|
||
*/
|
||
function getDx(d) {
|
||
return (d === 6) ? 1 : (d === 4) ? -1 : 0;
|
||
}
|
||
/**
|
||
* 指定方向のY要素を返す。
|
||
* @param {Number} d 方向(テンキー対応)
|
||
*/
|
||
function getDy(d) {
|
||
return (d === 2) ? 1 : (d === 8) ? -1 : 0;
|
||
}
|
||
/**
|
||
* 指定方向をflagに変換して返す。
|
||
* @param {Number} d 方向(テンキー対応)
|
||
*/
|
||
function getFlag(d) {
|
||
return 1 << (d / 2 - 1);
|
||
}
|
||
})(); |