-
-
Save agoaj/80699b34a3d53ab210e47c77d8719317 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* MIT License | |
* | |
* Copyright (c) 2017-2018 Altimit Community Contributors | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in all | |
* copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
* SOFTWARE. | |
*/ | |
//============================================================================= | |
// AltimitMovement.js | |
//============================================================================= | |
/*: | |
* @target mz | |
* @plugindesc Vector-based character movement and collision | |
* @author Altimit Community Contributors | |
* @url https://github.com/AltimitSystems/mv-plugins/tree/master/movement | |
* | |
* @param player | |
* @text Player | |
* @desc Parameters related to player character. | |
* | |
* @param player_collider_list | |
* @text Collider | |
* @desc Default collider list for player character. | |
* @parent player | |
* @type note | |
* @default "<circle cx='0.5' cy='0.7' r='0.25' />" | |
* | |
* @param player_circular_movement | |
* @text Normalize the movement? | |
* @desc Should the diagonal movement be the same distance as the straight movement? | |
* @parent player | |
* @type boolean | |
* @on Yes | |
* @off No | |
* @default true | |
* | |
* @param | |
* | |
* @param followers | |
* @text Followers | |
* @desc Parameters related to party followers. | |
* | |
* @param followers_distance | |
* @text Follow distance | |
* @desc Distance of 1 results in a tight chain. Distance of 2 will double the spacing. | |
* @parent followers | |
* @type number | |
* @min 0 | |
* @decimals 2 | |
* @default 1.50 | |
* | |
* @param followers_collider_list | |
* @text Collider | |
* @desc Default collider list for followers. | |
* @parent followers | |
* @type note | |
* @default "<circle cx='0.5' cy='0.7' r='0.25' />" | |
* | |
* @param followers_circular_movement | |
* @text Normalize the movement? | |
* @desc Should the diagonal movement be the same distance as the straight movement? | |
* @parent followers | |
* @type boolean | |
* @on Yes | |
* @off No | |
* @default true | |
* | |
* @param | |
* | |
* @param vehicles | |
* @text Vehicles | |
* @desc Parameters related to the vehicles. | |
* | |
* @param vehicles_boat_collider_list | |
* @text Boat collider | |
* @desc Default collider list for the boat. | |
* @parent vehicles | |
* @type note | |
* @default "<circle cx='0.5' cy='0.5' r='0.333' />" | |
* | |
* @param vehicles_ship_collider_list | |
* @text Ship collider | |
* @desc Default collider list for the ship. | |
* @parent vehicles | |
* @type note | |
* @default "<circle cx='0.5' cy='0.5' r='0.5' />" | |
* | |
* @param vehicles_airship_collider_list | |
* @text Airship collider | |
* @desc Default collider list for the airship. | |
* @parent vehicles | |
* @type note | |
* @default "<circle cx='0.5' cy='0.5' r='0.25' />" | |
* | |
* @param | |
* | |
* @param event | |
* @text Events | |
* @desc Parameters related to events. | |
* | |
* @param event_character_collider_list | |
* @text Character collider | |
* @desc Default collider list for character events. | |
* @parent event | |
* @type note | |
* @default "<circle cx='0.5' cy='0.7' r='0.25' />" | |
* | |
* @param event_tile_collider_list | |
* @text Tile collider | |
* @desc Default collider list for tile events. | |
* @parent event | |
* @type note | |
* @default "<rect x='0' y='0' width='1' height='1' />" | |
* | |
* @param | |
* | |
* @param presets | |
* @text Collider presets | |
* @desc Preset colliders to be referenced by events. | |
* @type note[] | |
* @default [] | |
* | |
* @param | |
* | |
* @param move_route | |
* @text Move route behaviour | |
* @desc Parameters related to character move routes. | |
* | |
* @param move_route_align_grid | |
* @text Align move-routes to grid? | |
* @desc If character is offset on a tile align them to the tile grid when moving. | |
* @parent move_route | |
* @type boolean | |
* @on Yes | |
* @off No | |
* @default true | |
* | |
* @param | |
* | |
* @param input_config | |
* @text Input config | |
* @desc Configuration for input method. | |
* | |
* @param input_config_enable_touch_mouse | |
* @text Use touch/mouse? | |
* @desc Enables pointer-based input. | |
* @parent input_config | |
* @type boolean | |
* @on Yes | |
* @off No | |
* @default true | |
* | |
* @param input_config_gamepad_mode | |
* @text Gamepad mode | |
* @desc Gamepad analogue stick input control. | |
* @parent input_config | |
* @type select | |
* @option Movement + Facing | |
* @value 3 | |
* @option Movement only | |
* @value 2 | |
* @option Facing only | |
* @value 1 | |
* @option Disabled | |
* @value 0 | |
* @default 3 | |
* | |
* @param | |
* | |
* @param play_test | |
* @text Play-testing | |
* @desc Parameters when running in Play-test mode. | |
* | |
* @param play_test_collision_mesh_caching | |
* @text Use cached collision? | |
* @desc Disabled caching will re-compile the collision mesh for maps that are in-development. | |
* @parent play_test | |
* @type boolean | |
* @on Yes | |
* @off No | |
* @default false | |
* | |
* | |
* @help | |
* | |
* | |
* Usage: | |
* Plugin will automatically apply when ON. | |
* | |
* About: | |
* Version 0.50 Beta | |
* Website https://github.com/AltimitSystems/mv-plugins/tree/master/movement | |
* @end | |
* ============================================================================= | |
* Plugin Commands | |
* ============================================================================= | |
* | |
* @command setPlayerCollider | |
* @text Change Player Collider | |
* @desc Change Player's Collider to another preset. | |
* | |
* @arg colliderPreset | |
* @text Change To | |
* @type text | |
* @default 1 | |
* @desc Change the collider to this preset(Defined in plugin settings). | |
* Numbers are treated as an index into the preset array. 0 is the default collider. | |
* Text will find a collider with a matching Name field. | |
* | |
* @command setThisCollider | |
* @text Change This Collider | |
* @desc Change this event's Collider to another preset. | |
* | |
* @arg colliderPreset | |
* @text Change To | |
* @type text | |
* @default 1 | |
* @desc Change the collider to this preset(Defined in plugin settings). | |
* Numbers are treated as an index into the preset array. 0 is the default collider. | |
* Text will find a collider with a matching Name field. | |
* | |
* @command setEventCollider | |
* @text Change Event Collider | |
* @desc Change an event's Collider to another preset. | |
* | |
* @arg eventId | |
* @text Event | |
* @type text | |
* @default 1 | |
* @desc Enter the event name or the ID number. | |
* | |
* @arg colliderPreset | |
* @text Change To | |
* @type text | |
* @default 1 | |
* @desc Change the collider to this preset(Defined in plugin settings). | |
* Numbers are treated as an index into the preset array. 0 is the default collider. | |
* Text will find a collider with a matching Name field. | |
* | |
* @command setVehicleCollider | |
* @text Change Vehicle Collider | |
* @desc Change a vehicle's Collider to another preset. | |
* | |
* @arg vehicleId | |
* @text Vehicle | |
* @type select | |
* @option Boat | |
* @value boat | |
* @option Ship | |
* @value ship | |
* @option Airship | |
* @value airship | |
* @default boat | |
* @desc Select the vehicle to change the collider for. | |
* | |
* @arg colliderPreset | |
* @text Change To | |
* @type text | |
* @default 1 | |
* @desc Change the collider to this preset(Defined in plugin settings). | |
* Numbers are treated as an index into the preset array. 0 is the default collider. | |
* Text will find a collider with a matching Name field. | |
* | |
* @command setFollowerCollider | |
* @text Change Follower Collider | |
* @desc Change a Follower's Collider to another preset. | |
* | |
* @arg followerId | |
* @text Follower | |
* @type select | |
* @option 1 | |
* @value 1 | |
* @option 2 | |
* @value 2 | |
* @option 3 | |
* @value 3 | |
* @default 1 | |
* @desc Select the follower to change the collider for. | |
* | |
* @arg colliderPreset | |
* @text Change To | |
* @type text | |
* @default 1 | |
* @desc Change the collider to this preset(Defined in plugin settings). | |
* Numbers are treated as an index into the preset array. 0 is the default collider. | |
* Text will find a collider with a matching Name field. | |
* | |
* | |
* @command setFollowersDistance | |
* @text Change Followers Distance | |
* @desc Change a Follower's follow distance from the player. | |
* | |
* @arg distance | |
* @text Following Distance | |
* @type number | |
* @decimals 2 | |
* @default 0.25 | |
* @desc The follow distance in tiles. | |
* | |
* @command setFollowersFollow | |
* @text Set Followers Can Follow | |
* @desc Change if followers can follow the player. | |
* | |
* @arg followerId | |
* @text Follower | |
* @type select | |
* @option 1 | |
* @value 1 | |
* @option 2 | |
* @value 2 | |
* @option 3 | |
* @value 3 | |
* @option All | |
* @value all | |
* @default 1 | |
* @desc Select the follower to change. | |
* | |
* @arg shouldFollow | |
* @text Should Follow? | |
* @type boolean | |
* @on Follow | |
* @off Don't Follow | |
* @default true | |
* @desc Select if the follower should follow the player. | |
* | |
* @command setMoveAlign | |
* @text Change Move Route Alignment | |
* @desc Change if move routes should align to the grid. | |
* | |
* @arg alignToGrid | |
* @text Align To Grid? | |
* @type boolean | |
* @on Align To Grid | |
* @off Don't Align To Grid | |
* @default true | |
* @desc Move route commands will align to the grid. | |
* | |
* | |
* @command move | |
* @text Move | |
* @desc Do an advanced movement command | |
* | |
* @arg moveCommand | |
* @text Move Command | |
* @type struct<MoveStep> | |
* @desc Enter advanced movement commands | |
* | |
* @arg wait | |
* @text Wait For Completion | |
* @type boolean | |
* @on Yes | |
* @off No | |
* @default true | |
* @desc Waits for all movement to finish | |
* | |
* @arg isSkippable | |
* @text Skip If Cannot Move | |
* @type boolean | |
* @on Yes | |
* @off No | |
* @default false | |
* @desc Skips any command that would move a character into an impassable location. | |
* | |
* | |
* @command setTouchMouse | |
* @text Change Touch/Mouse Input | |
* @desc Change if Touch/Mouse Input is enabled. | |
* | |
* @arg value | |
* @text Touch/Mouse Enabled | |
* @type boolean | |
* @default false | |
* @desc Allows the player can move their character with mouse or touchscreen input. | |
* | |
* ============================================================================= | |
* Struct Definitions | |
* ============================================================================= | |
*/ | |
/*~struct~MoveStep: | |
* | |
* @param mvr | |
* @text Mover | |
* @type select | |
* @default this | |
* @option Player | |
* @value player | |
* @option This | |
* @value this | |
* @option Event | |
* @value event | |
* @option Follower1 | |
* @value follower1 | |
* @option Follower2 | |
* @value follower2 | |
* @option Follower3 | |
* @value follower3 | |
* @option Boat | |
* @value boat | |
* @option Ship | |
* @value ship | |
* @option Airship | |
* @value airship | |
* | |
* @desc Select what you want to move. | |
* If you select event, also fill out the Mover Event Id field. | |
* | |
* @param dir | |
* @text Direction | |
* @type select | |
* @default random | |
* @option Random | |
* @value random | |
* @option ↑ | |
* @option ↗ | |
* @option → | |
* @option ↘ | |
* @option ↓ | |
* @option ↙ | |
* @option ← | |
* @option ↖ | |
* @option Forward | |
* @value forward | |
* @option Backward | |
* @value backward | |
* @option Away From Other | |
* @value away | |
* @option Towards Other | |
* @value towards | |
* | |
* @param dist | |
* @text Distance | |
* @type number | |
* @decimals 2 | |
* @default 1 | |
* @desc Distance to move in tiles. Or set to the text edge and the character will align to the current tiles edge. | |
* | |
* @param other | |
* @text Other | |
* @type select | |
* @default player | |
* @option Player | |
* @value player | |
* @option This | |
* @value this | |
* @option Event | |
* @value event | |
* @option Boat | |
* @value boat | |
* @option Ship | |
* @value ship | |
* @option Airship | |
* @value airship | |
* | |
* @param moverEventId | |
* @text Mover Event Id | |
* @type text | |
* @desc Id number or name of event to move. Mover must be set to Event or this will be ignored. | |
* | |
* @param otherEventId | |
* @text Other Event Id | |
* @type text | |
* @desc Id number or name of event to move around. Direction must be set to Event or this will be ignored. | |
*/ | |
( function() { | |
const pluginName = "AltimitMovement"; | |
var DOM_PARSER = new DOMParser(); | |
var PARAMETERS = PluginManager.parameters( 'AltimitMovement' ); | |
var GAME_PAD_THRESHOLD = 1 / 5; | |
var GAME_PAD_LIMIT = 1 - GAME_PAD_THRESHOLD; | |
/** | |
* PLAYER | |
*/ | |
var PLAYER; | |
( function() { | |
PLAYER = { | |
CIRCULAR_MOVEMENT: ( PARAMETERS['player_circular_movement'] != 'false' ), | |
}; | |
var colliderList = PARAMETERS['player_collider_list']; | |
if ( colliderList ) { | |
PLAYER.COLLIDER_LIST = '<collider>' + JSON.parse( colliderList ) + '</collider>'; | |
} else { | |
PLAYER.COLLIDER_LIST = "<collider><circle cx='0.5' cy='0.7' r='0.25' /></collider>"; | |
} | |
} )(); | |
/** | |
* FOLLOWERS | |
*/ | |
var FOLLOWERS; | |
( function() { | |
FOLLOWERS = { | |
DISTANCE: Number( PARAMETERS['followers_distance'] ), | |
CIRCULAR_MOVEMENT: ( PARAMETERS['followers_circular_movement'] != 'false' ), | |
}; | |
var colliderList = PARAMETERS['followers_collider_list']; | |
if ( colliderList ) { | |
FOLLOWERS.COLLIDER_LIST = '<collider>' + JSON.parse( colliderList ) + '</collider>'; | |
} else { | |
FOLLOWERS.COLLIDER_LIST = "<collider><circle cx='0.5' cy='0.7' r='0.25' /></collider>"; | |
} | |
} )(); | |
/** | |
* VEHICLES | |
*/ | |
var VEHICLES; | |
( function() { | |
VEHICLES = {}; | |
var colliderList = PARAMETERS['vehicles_boat_collider_list']; | |
if ( colliderList ) { | |
VEHICLES.BOAT_COLLIDER_LIST = '<collider>' + JSON.parse( colliderList ) + '</collider>'; | |
} else { | |
VEHICLES.BOAT_COLLIDER_LIST = "<collider><circle cx='0.5' cy='0.5' r='0.333' /></collider>"; | |
} | |
var colliderList = PARAMETERS['vehicles_ship_collider_list']; | |
if ( colliderList ) { | |
VEHICLES.SHIP_COLLIDER_LIST = '<collider>' + JSON.parse( colliderList ) + '</collider>'; | |
} else { | |
VEHICLES.SHIP_COLLIDER_LIST = "<collider><circle cx='0.5' cy='0.5' r='0.5' /></collider>"; | |
} | |
var colliderList = PARAMETERS['vehicles_airship_collider_list']; | |
if ( colliderList ) { | |
VEHICLES.AIRSHIP_COLLIDER_LIST = '<collider>' + JSON.parse( colliderList ) + '</collider>'; | |
} else { | |
VEHICLES.AIRSHIP_COLLIDER_LIST = "<collider><circle cx='0.5' cy='0.5' r='0.25' /></collider>"; | |
} | |
} )(); | |
/** | |
* EVENT | |
*/ | |
var EVENT; | |
( function() { | |
EVENT = {}; | |
var colliderList = PARAMETERS['event_character_collider_list']; | |
if ( colliderList ) { | |
EVENT.CHARACTER_COLLIDER_LIST = '<collider>' + JSON.parse( colliderList ) + '</collider>'; | |
} else { | |
EVENT.CHARACTER_COLLIDER_LIST = "<collider><circle cx='0.5' cy='0.7' r='0.25' /></collider>"; | |
} | |
var colliderList = PARAMETERS['event_tile_collider_list']; | |
if ( colliderList ) { | |
EVENT.TILE_COLLIDER_LIST = '<collider>' + JSON.parse( colliderList ) + '</collider>'; | |
} else { | |
EVENT.TILE_COLLIDER_LIST = "<collider><rect x='0' y='0' width='1' height='1' /></collider>"; | |
} | |
} )(); | |
/** | |
* PRESETS | |
*/ | |
var PRESETS; | |
( function() { | |
var presets = PARAMETERS['presets']; | |
if ( presets ) { | |
PRESETS = JSON.parse( presets ); | |
} else { | |
PRESETS = []; | |
} | |
} )(); | |
var MOVE_ROUTE = { | |
ALIGN_GRID: ( PARAMETERS['move_route_align_grid'] != 'false' ), | |
}; | |
var INPUT_CONFIG = { | |
ENABLE_TOUCH_MOUSE: ( PARAMETERS['input_config_enable_touch_mouse'] != 'false' ), | |
GAMEPAD_MODE: parseInt( PARAMETERS['input_config_gamepad_mode'] ), | |
}; | |
var PLAY_TEST = { | |
COLLISION_MESH_CACHING: ( PARAMETERS['play_test_collision_mesh_caching'] != 'false' ), | |
}; | |
/** | |
* Game_System | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
var Game_System_initialize = Game_System.prototype.initialize; | |
Game_System.prototype.initialize = function() { | |
Game_System_initialize.call( this ); | |
this._eventColliders = []; | |
this._staticMoveAlignGrid = MOVE_ROUTE.ALIGN_GRID; | |
this._moveAlignGrid = MOVE_ROUTE.ALIGN_GRID; | |
this._staticFollowerDistance = FOLLOWERS.DISTANCE; | |
this._followerDistance = FOLLOWERS.DISTANCE; | |
this._staticEnableTouchMouse = INPUT_CONFIG.ENABLE_TOUCH_MOUSE; | |
this._enableTouchMouse = INPUT_CONFIG.ENABLE_TOUCH_MOUSE; | |
}; | |
Game_System.prototype.createColliderFromXML = function( xml ) { | |
return Collider.createFromXML( xml ); | |
}; | |
} )(); | |
} )(); | |
/** | |
* Game_Interpreter | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
var Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand; | |
Game_Interpreter.prototype.pluginCommand = function( command, args ) { | |
Game_Interpreter_pluginCommand.call( this, command, args ); | |
if ( command === 'AltMovement' ) { | |
switch ( args[0] ) { | |
case 'collider': | |
this.altMovementCollider( args ); | |
break; | |
case 'followers': | |
switch ( args[1] ) { | |
case 'set': | |
switch ( args[2] ) { | |
case 'distance': | |
$gameSystem._followerDistance = Number( args[3] ); | |
break; | |
default: | |
var index = parseInt( args[2] ); | |
switch ( args[3] ) { | |
case 'following': | |
if ( args[4] ) { | |
switch ( args[4].toLowerCase() ) { | |
case 'disable': | |
case 'off': | |
case 'false': | |
case 'no': | |
$gamePlayer.followers().follower( index ).setFrozen( true ); | |
break; | |
case 'enable': | |
case 'on': | |
case 'true': | |
case 'yes': | |
$gamePlayer.followers().follower( index ).setFrozen( false ); | |
break; | |
} | |
} else { | |
$gamePlayer.followers().follower( index ).setFrozen( false ); | |
} | |
break; | |
} | |
break; | |
} | |
break; | |
} | |
break; | |
case 'move': | |
this.altMovementMoveCharacter( args ); | |
break; | |
case 'move_align': | |
switch ( args[1] ) { | |
case 'set': | |
switch ( args[2].toLowerCase() ) { | |
case 'disable': | |
case 'off': | |
case 'false': | |
case 'no': | |
$gameSystem._moveAlignGrid = false; | |
break; | |
case 'enable': | |
case 'on': | |
case 'true': | |
case 'yes': | |
$gameSystem._moveAlignGrid = true; | |
break; | |
} | |
break; | |
} | |
break; | |
case 'input': | |
switch ( args[1] ) { | |
case 'touch': | |
case 'mouse': | |
switch ( args[2].toLowerCase() ) { | |
case 'disable': | |
case 'off': | |
case 'false': | |
case 'no': | |
$gameSystem._enableTouchMouse = false; | |
break; | |
case 'enable': | |
case 'on': | |
case 'true': | |
case 'yes': | |
$gameSystem._enableTouchMouse = true; | |
break; | |
} | |
break; | |
} | |
break; | |
} | |
} | |
}; | |
var Game_Interpreter_updateWaitMode = Game_Interpreter.prototype.updateWaitMode; | |
Game_Interpreter.prototype.updateWaitMode = function() { | |
if ( 'target' == this._waitMode ) { | |
return this._character._moveTarget; | |
} | |
return Game_Interpreter_updateWaitMode.call( this ); | |
}; | |
} )(); | |
/** | |
* Extensions | |
*/ | |
( function() { | |
Game_Interpreter.prototype.altMovementStringArgs = function( args ) { | |
if(Array.isArray(args)) | |
return args; | |
var str = args.join( ' ' ); | |
var args = []; | |
var readingPart = false; | |
var part = ''; | |
for ( var ii = 0; ii < str.length; ii++ ) { | |
if ( str.charAt( ii ) === ' ' && !readingPart ) { | |
args.push( part ); | |
part = ''; | |
} else { | |
if ( str.charAt( ii ) === '\"' ) { | |
readingPart = !readingPart; | |
} | |
part += str.charAt( ii ); | |
} | |
} | |
args.push( part ); | |
return args; | |
}; | |
Game_Interpreter.prototype.altMovementCommandToDirection = function( command ) { | |
var gc = Game_Character; | |
switch ( command ) { | |
case gc.ROUTE_MOVE_DOWN: | |
return 2; | |
case gc.ROUTE_MOVE_LEFT: | |
return 4; | |
case gc.ROUTE_MOVE_RIGHT: | |
return 6; | |
case gc.ROUTE_MOVE_UP: | |
return 8; | |
case gc.ROUTE_MOVE_LOWER_L: | |
return 1; | |
case gc.ROUTE_MOVE_LOWER_R: | |
return 3; | |
case gc.ROUTE_MOVE_UPPER_L: | |
return 7; | |
case gc.ROUTE_MOVE_UPPER_R: | |
return 9; | |
case gc.ROUTE_MOVE_RANDOM: | |
return 1 + Math.randomInt( 8 ); | |
case gc.ROUTE_MOVE_FORWARD: | |
return subject._direction; | |
case gc.ROUTE_MOVE_BACKWARD: | |
return subject.reverseDir( subject._direction ); | |
default: | |
return 5; | |
} | |
}; | |
Game_Interpreter.prototype.altMovementCharacterEdgeDxDy = function( subject, dx, dy ) { | |
var stepDistance; | |
var box = subject.collider().aabbox; | |
if ( dx && dy ) { | |
var xd; | |
if ( dx < 0 ) { | |
var px = subject.x + box.left; | |
xd = Math.floor( px ) - px; | |
} else { | |
var px = subject.x + box.right; | |
xd = Math.ceil( px ) - px; | |
} | |
var yd; | |
if ( dy < 0 ) { | |
var py = subject.y + box.top; | |
yd = Math.floor( py ) - py; | |
} else { | |
var py = subject.y + box.bottom; | |
yd = Math.ceil( py ) - py; | |
} | |
stepDistance = xd < yd ? xd : yd; | |
} else if ( dx ) { | |
if ( dx < 0 ) { | |
var px = subject.x + box.left; | |
stepDistance = Math.floor( px ) - px; | |
} else { | |
var px = subject.x + box.right; | |
stepDistance = Math.ceil( px ) - px; | |
} | |
} else { | |
if ( dy < 0 ) { | |
var py = subject.y + box.top; | |
stepDistance = Math.floor( py ) - py; | |
} else { | |
var py = subject.y + box.bottom; | |
stepDistance = Math.ceil( py ) - py; | |
} | |
} | |
return stepDistance; | |
}; | |
Game_Interpreter.prototype.altMovementProcessMoveCommand = function( subject, command, distance, options, object ) { | |
$gameMap.refreshIfNeeded(); | |
this._character = subject; | |
if ( options.wait ) { | |
this.setWaitMode( 'target' ); | |
} | |
subject._moveTargetSkippable = options.skip; | |
subject._moveTarget = true; | |
if ( object ) { | |
var dx = object.x - subject.x; | |
var dy = object.y - subject.y; | |
var length = Math.sqrt( dx * dx + dy * dy ); | |
dx /= length; | |
dy /= length; | |
var stepDistance; | |
if ( 'edge' == distance ) { | |
stepDistance = this.altMovementCharacterEdgeDxDy( subject, dx, dy ); | |
} else { | |
stepDistance = Number( distance ); | |
} | |
if ( command == Game_Character.ROUTE_MOVE_AWAY ) { | |
stepDistance *= -1; | |
} | |
subject._moveTargetX = subject.x + dx * stepDistance; | |
subject._moveTargetY = subject.y + dy * stepDistance; | |
} else { | |
var direction = this.altMovementCommandToDirection( command ); | |
var dx = Direction.isLeft( direction ) ? -1 : ( Direction.isRight( direction ) ? 1 : 0 ); | |
var dy = Direction.isUp( direction ) ? -1 : ( Direction.isDown( direction ) ? 1 : 0 ); | |
var stepDistance; | |
if ( 'edge' == distance ) { | |
stepDistance = this.altMovementCharacterEdgeDxDy( subject, dx, dy ); | |
} else { | |
stepDistance = Number( distance ); | |
} | |
subject._moveTargetX = subject.x + dx * stepDistance; | |
subject._moveTargetY = subject.y + dy * stepDistance; | |
} | |
}; | |
Game_Interpreter.prototype.altMovementMoveCharacter = function( args ) { | |
args = this.altMovementStringArgs( args ); | |
var subject = this.altMovementGetTargetCharacter( args[1] ); | |
var command = this.altMovementGetMoveCommand( args[2] ); | |
switch ( command ) { | |
case Game_Character.ROUTE_MOVE_AWAY: | |
case Game_Character.ROUTE_MOVE_TOWARD: | |
var object = this.altMovementGetTargetCharacter( args[3] ); | |
var options = { | |
wait: args[5] == 'wait' || args[6] == 'wait', | |
skip: args[5] == 'skip' || args[6] == 'skip' || args[5] == 'skippable' || args[6] == 'skippable', | |
}; | |
this.altMovementProcessMoveCommand( subject, command, args[4], options, object ); | |
break; | |
default: | |
var options = { | |
wait: args[4] == 'wait' || args[5] == 'wait', | |
skip: args[4] == 'skip' || args[5] == 'skip' || args[4] == 'skippable' || args[5] == 'skippable', | |
}; | |
this.altMovementProcessMoveCommand( subject, command, args[3], options ); | |
break; | |
} | |
}; | |
Game_Interpreter.prototype.altMovementCollider = function( args ) { | |
args = this.altMovementStringArgs( args ); | |
switch ( args[1] ) { | |
case 'set': | |
this.altMovementColliderSet( args ); | |
break; | |
} | |
}; | |
Game_Interpreter.prototype.altMovementColliderSet = function( args ) { | |
var target = this.altMovementGetTargetCharacter( args[2] ); | |
if ( !target ) { | |
return; | |
} | |
var presetIndex = Number( args[3] ); | |
if ( isNaN( presetIndex ) ) { | |
target.setCollider( Collider.getPreset( args[3].substring( 1, args[3].length - 1 ) ) ); | |
target._hasCustomCollider = true; | |
} else { | |
target.setCollider( Collider.getPreset( presetIndex ) ); | |
target._hasCustomCollider = true; | |
} | |
}; | |
Game_Interpreter.prototype.altMovementGetMoveCommand = function( cmdStr ) { | |
switch ( cmdStr ) { | |
case 'down_left': case 'bottom_left': case 'lower_left': case 'lower_l': | |
case 'left_down': case 'left_bottom': case 'left_lower': case 'l_lower': | |
case 'south_west': case 'west_south': case '1': case '↙': | |
return Game_Character.ROUTE_MOVE_LOWER_L; | |
case 'down': case 'bottom': case 'lower': case 'south': case '2': case '↓': | |
return Game_Character.ROUTE_MOVE_DOWN; | |
case 'down_right': case 'bottom_right': case 'lower_right': case 'lower_r': | |
case 'right_down': case 'right_bottom': case 'right_lower': case 'r_lower': | |
case 'south_east': case 'east_south': case '3': case '↘': | |
return Game_Character.ROUTE_MOVE_LOWER_R; | |
case 'left': case 'west': case '4': case '←': | |
return Game_Character.ROUTE_MOVE_LEFT; | |
case 'right': case 'east': case '6': case '→': | |
return Game_Character.ROUTE_MOVE_RIGHT; | |
case 'up_left': case 'top_left': case 'upper_left': case 'upper_l': | |
case 'left_up': case 'left_top': case 'left_upper': case 'l_upper': | |
case 'north_west': case 'west_north': case '7': case '↖': | |
return Game_Character.ROUTE_MOVE_UPPER_L; | |
case 'up': case 'top': case 'upper': case 'north': case '8': case '↑': | |
return Game_Character.ROUTE_MOVE_UP; | |
case 'up_right': case 'top_right': case 'upper_right': case 'upper_r': | |
case 'right_up': case 'right_top': case 'right_upper': case 'r_upper': | |
case 'north_east': case 'east_north': case '9': case '↗': | |
return Game_Character.ROUTE_MOVE_UPPER_R; | |
case 'away': case 'away_from': | |
return Game_Character.ROUTE_MOVE_AWAY; | |
case 'toward': case 'towards': case 'toward_to': | |
return Game_Character.ROUTE_MOVE_TOWARD; | |
case 'forward': case 'forwards': | |
return Game_Character.ROUTE_MOVE_FORWARD; | |
case 'backward': case 'backwards': case 'back': | |
return Game_Character.ROUTE_MOVE_BACKWARD; | |
case 'random': case 'randomly': | |
return Game_Character.ROUTE_MOVE_RANDOM; | |
default: | |
return null; | |
} | |
}; | |
Game_Interpreter.prototype.altMovementGetTargetCharacter = function( target ) { | |
if ( target.startsWith( '\"' ) && target.endsWith( '\"' ) ) { | |
// Event name | |
var eventName = target.substring( 1, target.length - 1 ); | |
for ( var ii = 0; ii < $dataMap.events.length; ii++ ) { | |
if ( $dataMap.events[ii] && $dataMap.events[ii].name === eventName ) { | |
return $gameMap.event( $dataMap.events[ii].id ); | |
} | |
} | |
} else { | |
// System name | |
switch ( target ) { | |
case 'this': | |
var eventId = this._eventId; | |
// This Event ID # | |
return $gameMap.event( eventId ); | |
case 'player': | |
return $gamePlayer; | |
case 'boat': | |
return $gameMap.boat(); | |
case 'ship': | |
return $gameMap.ship(); | |
case 'airship': | |
return $gameMap.airship(); | |
default: | |
if ( target.startsWith( 'follower') ) { | |
var index = Number( target.substring( 8 ) ); | |
// Follower index | |
return $gamePlayer.followers().follower( index ); | |
} else { | |
var eventId = Number( target ); | |
// Event ID # | |
return $gameMap.event( eventId ); | |
} | |
} | |
} | |
return null; | |
}; | |
} )(); | |
} )(); | |
/** | |
* Game_CharacterBase | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
var Game_CharacterBase_update = Game_CharacterBase.prototype.update; | |
Game_CharacterBase.prototype.update = function() { | |
if ( this._moveTarget ) { | |
var dx = $gameMap.directionX( this._x, this._moveTargetX ); | |
var dy = $gameMap.directionY( this._y, this._moveTargetY ); | |
var length = Math.sqrt( dx * dx + dy * dy ); | |
if ( length <= this.stepDistance ) { | |
this._moveTarget = false; | |
this._moveTargetSkippable = false; | |
this.setDirectionFix( this._wasDirectionFixed ); | |
this._x = $gameMap.roundX( this._moveTargetX ); | |
this._y = $gameMap.roundY( this._moveTargetY ); | |
} else { | |
dx /= length; | |
dy /= length; | |
this.moveVector( dx * this.stepDistance, dy * this.stepDistance ); | |
if ( !this.isMovementSucceeded() ) { | |
if ( this._moveTargetSkippable || ( !!this._moveRoute && this._moveRoute.skippable ) ) { | |
this._moveTarget = false; | |
this._moveTargetSkippable = false; | |
this.setDirectionFix( this._wasDirectionFixed ); | |
} | |
} | |
} | |
} | |
Game_CharacterBase_update.call( this ); | |
}; | |
Game_CharacterBase.prototype.isOnLadder = function() { | |
var aabbox = this.collider().aabbox; | |
if ( aabbox.left >= 0 && aabbox.right <= 1 ) { | |
// To use ladder the bounding box must fit on a tile | |
return false; | |
} | |
// If middle is on ladder | |
if ( $gameMap.isLadder( $gameMap.roundX( this._x + ( aabbox.left + aabbox.right ) / 2 ), $gameMap.roundY( this._y + ( aabbox.top + aabbox.bottom ) / 2 ) ) ) { | |
// If bottom middle is on ladder | |
if ( $gameMap.isLadder( $gameMap.roundX( this._x + ( aabbox.left + aabbox.right ) / 2 ), $gameMap.roundY( this._y + aabbox.bottom ) ) ) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
Game_CharacterBase.prototype.moveStraight = function( d ) { | |
var vy = Direction.isUp( d ) ? -1 : ( Direction.isDown( d ) ? 1 : 0 ); | |
var vx = Direction.isLeft( d ) ? -1 : ( Direction.isRight( d ) ? 1 : 0 ); | |
if ( this._circularMovement ) { | |
var length = Math.sqrt( vx * vx + vy * vy ); | |
vx /= length; | |
vy /= length; | |
} | |
this.moveVector( vx * this.stepDistance, vy * this.stepDistance ); | |
}; | |
Game_CharacterBase.prototype.moveDiagonally = function( horz, vert ) { | |
var vy = Direction.isUp( vert ) ? -1 : ( Direction.isDown( vert ) ? 1 : 0 ); | |
var vx = Direction.isLeft( horz ) ? -1 : ( Direction.isRight( horz ) ? 1 : 0 ); | |
if ( this._circularMovement ) { | |
var length = Math.sqrt( vx * vx + vy * vy ); | |
vx /= length; | |
vy /= length; | |
} | |
this.moveVector( vx * this.stepDistance, vy * this.stepDistance ); | |
}; | |
var Game_CharacterBase_isMoving = Game_CharacterBase.prototype.isMoving; | |
Game_CharacterBase.prototype.isMoving = function() { | |
return Game_CharacterBase_isMoving.call( this ) || this._isMoving; | |
}; | |
var Game_CharacterBase_updateAnimation = Game_CharacterBase.prototype.updateAnimation; | |
Game_CharacterBase.prototype.updateAnimation = function() { | |
Game_CharacterBase_updateAnimation.call( this ); | |
this._wasMoving = this._isMoving; | |
this._isMoving = this._x !== this._realX || this._y !== this._realY; | |
if ( !this._isMoving ) { | |
this.refreshBushDepth(); | |
} | |
}; | |
Game_CharacterBase.prototype.isOnBush = function() { | |
var aabbox = this.collider().aabbox; | |
// If middle is in bush | |
if ( $gameMap.isBush( $gameMap.roundX( this._x + ( aabbox.left + aabbox.right ) / 2 ), $gameMap.roundY( this._y + ( aabbox.top + aabbox.bottom ) / 2 ) ) ) { | |
// If bottom middle is in bush | |
if ( $gameMap.isBush( $gameMap.roundX( this._x + ( aabbox.left + aabbox.right ) / 2 ), $gameMap.roundY( this._y + aabbox.bottom ) ) ) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
Game_CharacterBase.prototype.canPass = function( x, y, d ) { | |
if ( this.isThrough() || this.isDebugThrough() ) { | |
return true; | |
} | |
var x2 = $gameMap.roundXWithDirection( x, d ); | |
var y2 = $gameMap.roundYWithDirection( y, d ); | |
if ( !$gameMap.canWalk( this, x2, y2 ) ) { | |
return false; | |
} | |
return true; | |
}; | |
Game_CharacterBase.prototype.canPassDiagonally = function( x, y, horz, vert ) { | |
if ( this.isThrough() || this.isDebugThrough() ) { | |
return true; | |
} | |
var x2 = $gameMap.roundXWithDirection( x, horz ); | |
var y2 = $gameMap.roundYWithDirection( y, vert ); | |
if ( !$gameMap.canWalk( this, x2, y2 ) ) { | |
return false; | |
} | |
return true; | |
}; | |
var Game_CharacterBase_setDirection = Game_CharacterBase.prototype.setDirection; | |
Game_CharacterBase.prototype.setDirection = function( d ) { | |
Game_CharacterBase_setDirection.call( this, d ); | |
this._direction8 = this._direction; | |
}; | |
var Game_CharacterBase_screenX = Game_CharacterBase.prototype.screenX; | |
Game_CharacterBase.prototype.screenX = function() { | |
var round = Math.round; | |
Math.round = Math.floor; | |
var val = Game_CharacterBase_screenX.call( this ); | |
Math.round = round; | |
return val; | |
}; | |
var Game_CharacterBase_screenY = Game_CharacterBase.prototype.screenY; | |
Game_CharacterBase.prototype.screenY = function() { | |
var round = Math.round; | |
Math.round = Math.floor; | |
var val = Game_CharacterBase_screenY.call( this ); | |
Math.round = round; | |
return val; | |
}; | |
} )(); | |
/** | |
* Extensions | |
*/ | |
( function() { | |
Object.defineProperties( Game_CharacterBase.prototype, { | |
stepDistance: { get: function() { return this.distancePerFrame(); }, configurable: true }, | |
} ); | |
Game_CharacterBase.prototype.collidableWith = function( character ) { | |
return !!character | |
&& character !== this | |
&& character.isNormalPriority() | |
&& this.isNormalPriority() | |
&& !this.isThrough() | |
&& ( !character.isVisible ? true : character.isVisible() ) | |
&& ( !this.vehicle ? true : this.vehicle() !== character ) | |
&& ( !this.followers ? true : !this.followers().contains( character ) ) | |
&& ( character instanceof Game_Follower ? true : !character.isThrough() ) | |
&& !( this instanceof Game_Follower ? character instanceof Game_Follower : false ) | |
&& !( this instanceof Game_Follower ? character instanceof Game_Player : false ) | |
&& !( this instanceof Game_Vehicle ? character instanceof Game_Player : false ) | |
&& !( this instanceof Game_Vehicle ? character instanceof Game_Follower : false ) | |
&& ( character instanceof Game_Vehicle ? character._mapId === $gameMap.mapId() : true ); | |
} | |
Game_CharacterBase.prototype.moveVectorCharacters = function( owner, collider, characters, loopMap, move ) { | |
characters.forEach( function( character ) { | |
var characterX = character._x; | |
var characterY = character._y; | |
if ( loopMap[character] == 1 ) { characterX += $gameMap.width(); } | |
else if ( loopMap[character] == 2 ) { characterX -= $gameMap.width(); } | |
else if ( loopMap[character] == 3 ) { characterY += $gameMap.height(); } | |
else if ( loopMap[character] == 4 ) { characterY -= $gameMap.height(); } | |
else if ( loopMap[character] == 5 ) { characterX += $gameMap.width(); characterY += $gameMap.height(); } | |
else if ( loopMap[character] == 6 ) { characterX -= $gameMap.width(); characterY += $gameMap.height(); } | |
else if ( loopMap[character] == 7 ) { characterX += $gameMap.width(); characterY -= $gameMap.height(); } | |
else if ( loopMap[character] == 8 ) { characterX -= $gameMap.width(); characterY -= $gameMap.height(); } | |
move = Collider.move( owner._x, owner._y, collider, characterX, characterY, character.collider(), move ); | |
if ( move.x === 0 && move.y === 0 ) { | |
return; | |
} | |
} ); | |
}; | |
Game_CharacterBase.prototype.moveVectorMap = function( owner, collider, bboxTests, move, vx, vy ) { | |
for ( var ii = 0; ii < bboxTests.length; ii++ ) { | |
var offsetX = 0; | |
var offsetY = 0; | |
if ( bboxTests[ii].type == 1 ) { offsetX += $gameMap.width(); } | |
else if ( bboxTests[ii].type == 2 ) { offsetX -= $gameMap.width(); } | |
else if ( bboxTests[ii].type == 3 ) { offsetY += $gameMap.height(); } | |
else if ( bboxTests[ii].type == 4 ) { offsetY -= $gameMap.height(); } | |
else if ( bboxTests[ii].type == 5 ) { offsetX += $gameMap.width(); offsetY += $gameMap.height(); } | |
else if ( bboxTests[ii].type == 6 ) { offsetX -= $gameMap.width(); offsetY += $gameMap.height(); } | |
else if ( bboxTests[ii].type == 7 ) { offsetX += $gameMap.width(); offsetY -= $gameMap.height(); } | |
else if ( bboxTests[ii].type == 8 ) { offsetX -= $gameMap.width(); offsetY -= $gameMap.height(); } | |
var mapColliders = Collider.polygonsWithinColliderList( bboxTests[ii].x + vx, bboxTests[ii].y + vy, bboxTests[ii].aabbox, 0, 0, $gameMap.collisionMesh( this._collisionType ) ); | |
if ( mapColliders.length > 0 ) { | |
if ( move.x !== 0 ) { | |
var sigMove = { x: move.x, y: 0 }; | |
mapColliders.forEach( function( mapCollider ) { | |
sigMove = Collider.move( owner._x, owner._y, collider, offsetX, offsetY, mapCollider, sigMove ); | |
} ); | |
move.x = sigMove.x; | |
} | |
mapColliders.forEach( function( mapCollider ) { | |
move = Collider.move( owner._x, owner._y, collider, offsetX, offsetY, mapCollider, move ); | |
} ); | |
} | |
} | |
}; | |
Game_CharacterBase.prototype.moveVector = function( vx, vy ) { | |
var move; | |
var characterCollided = false; | |
if ( this.isThrough() || this.isDebugThrough() ) { | |
var aabbox = this.collider().aabbox; | |
move = { x: 0, y: 0 }; | |
if ( !$gameMap.isLoopHorizontal() && this._x + vx + aabbox.left < 0 ) { | |
move.x = 0 - ( this._x + aabbox.left ); | |
} else if ( !$gameMap.isLoopHorizontal() && this._x + vx + aabbox.right > $gameMap.width() ) { | |
move.x = $gameMap.width() - ( this._x + aabbox.right ); | |
} else { | |
move.x = vx; | |
} | |
if ( !$gameMap.isLoopVertical() && this._y + vy + aabbox.top < 0 ) { | |
move.y = 0 - ( this._y + aabbox.top ); | |
} else if ( !$gameMap.isLoopVertical() && this._y + vy + aabbox.bottom > $gameMap.height() ) { | |
move.y = $gameMap.height() - ( this._y + aabbox.bottom ); | |
} else { | |
move.y = vy; | |
} | |
} else { | |
var owner = this; | |
var collider = owner.collider(); | |
var bboxTests = $gameMap.getAABBoxTests( this, vx, vy ); | |
// Gather any solid characters within the movement bounding box | |
var loopMap = {}; | |
var characters = $gameMap.characters().filter( function( character ) { | |
if ( owner === $gamePlayer && owner.followers().contains( character ) ) { | |
return false; | |
} | |
if ( owner.collidableWith( character ) ) { | |
for ( var ii = 0; ii < bboxTests.length; ii++ ) { | |
if ( Collider.aabboxCheck( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, character._x, character._y, character.collider().aabbox, vx, vy ) ) { | |
loopMap[character] = bboxTests[ii].type; | |
return true; | |
} | |
} | |
} | |
return false; | |
} ); | |
move = { x: vx, y: vy }; | |
// Test collision with characters | |
this.moveVectorCharacters( owner, collider, characters, loopMap, move ); | |
if ( move.x !== vx || move.y !== vy ) { | |
// Collided with character, disable direction change | |
characterCollided = true; | |
} | |
// Test collision with map | |
this.moveVectorMap( owner, collider, bboxTests, move, vx, vy ); | |
} | |
// Resolve too much precision | |
move.x = Math.floor( move.x * Collider.PRECISION ) / Collider.PRECISION; | |
move.y = Math.floor( move.y * Collider.PRECISION ) / Collider.PRECISION; | |
// Special ladder behaviour | |
if ( this.isOnLadder() && ( this.isInAirship ? !this.isInAirship() : true ) ) { | |
var tileX = Math.round( this._x ); | |
if ( !$gameMap.isPassable( tileX, this._y + move.y, Direction.LEFT ) ) { | |
if ( !$gameMap.isPassable( tileX, this._y + move.y, Direction.RIGHT ) ) { | |
move.x = tileX - this._x; | |
} | |
} | |
} | |
var length = Math.sqrt( move.x * move.x + move.y * move.y ); | |
if ( length > Collider.I_PRECISION ) { | |
this._x = $gameMap.roundX( this._x + move.x ); | |
this._y = $gameMap.roundY( this._y + move.y ); | |
this._realX = this._x - move.x; | |
this._realY = this._y - move.y; | |
this.setMovementSuccess( true ); | |
if ( characterCollided ) { | |
this.setDirectionVector( vx, vy ); | |
} else { | |
this.setDirectionVector( move.x, move.y ); | |
} | |
this.increaseSteps(); | |
this._isMoving = true; | |
this.checkEventTriggerTouchFrontVector( move.x, move.y ); | |
} else { | |
this.setMovementSuccess( false ); | |
this.setDirectionVector( vx, vy ); | |
this._isMoving = false; | |
this.checkEventTriggerTouchFrontVector( vx, vy ); | |
} | |
}; | |
Game_CharacterBase.prototype.setDirectionVector = function( vx, vy ) { | |
if ( this.isDirectionFixed() ) { | |
return; | |
} | |
var direction = Math.atan2( vy, vx ) / Math.PI; | |
var direct = false; | |
if ( direction >= -0.2 && direction < 0.2 ) { | |
// East | |
this.setDirection( Direction.RIGHT ); | |
direct = true; | |
} else if ( direction >= 0.3 && direction < 0.7 ) { | |
// South | |
this.setDirection( Direction.DOWN ); | |
direct = true; | |
} else if ( direction >= -0.7 && direction < -0.3 ) { | |
// North | |
this.setDirection( Direction.UP ); | |
direct = true; | |
} else if ( direction >= -1.2 && direction < -0.8 ) { | |
// West | |
this.setDirection( Direction.LEFT ); | |
direct = true; | |
} else if ( direction >= 0.8 && direction < 1.2 ) { | |
// West | |
this.setDirection( Direction.LEFT ); | |
direct = true; | |
} | |
if ( !direct ) { | |
var dx = vx > 0 ? Direction.RIGHT : ( vx ? Direction.LEFT : 0 ); | |
var dy = vy > 0 ? Direction.DOWN : ( vy ? Direction.UP : 0 ); | |
if ( dx && dy ) { | |
if ( this._direction === this.reverseDir( dx ) ) { | |
this.setDirection( dx ); | |
} else if ( this._direction === this.reverseDir( dy ) ) { | |
this.setDirection( dy ); | |
} else { | |
this.resetStopCount(); | |
} | |
} else { | |
this.setDirection( dx || dy ); | |
} | |
} | |
var direction8 = Math.round( ( direction + 1 ) * 4 ) % 8; // 8 directions | |
switch ( direction8 ) { | |
case 0: | |
this._direction8 = Direction.LEFT; | |
break; | |
case 1: | |
this._direction8 = Direction.UP_LEFT; | |
break; | |
case 2: | |
this._direction8 = Direction.UP; | |
break; | |
case 3: | |
this._direction8 = Direction.UP_RIGHT; | |
break; | |
case 4: | |
this._direction8 = Direction.RIGHT; | |
break; | |
case 5: | |
this._direction8 = Direction.DOWN_RIGHT; | |
break; | |
case 6: | |
this._direction8 = Direction.DOWN; | |
break; | |
case 7: | |
this._direction8 = Direction.DOWN_LEFT; | |
break; | |
} | |
}; | |
Game_CharacterBase.prototype.checkEventTriggerTouchFrontVector = function( vx, vy ) { | |
this.checkEventTriggerTouch( this._x + vx, this._y + vy ); | |
}; | |
Game_CharacterBase.prototype.align = function() { | |
this._x = this._x | 0; | |
this._y = this._y | 0; | |
}; | |
Game_CharacterBase.prototype.collider = function() { | |
return this._collider || Collider.sharedTile(); | |
}; | |
Game_CharacterBase.prototype.setCollider = function( collider ) { | |
this._collider = collider; | |
}; | |
Game_CharacterBase.prototype.direction8 = function() { | |
return this._direction8; | |
}; | |
} )(); | |
} )(); | |
/** | |
* Game_Character | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
Game_Character.prototype.updateRoutineMove = function() { | |
if ( this._moveTarget ) { | |
var moveRoute = this._moveRoute; | |
if ( !moveRoute.skippable || this._wasMoving ) { | |
return; | |
} | |
} | |
if ( this._waitCount > 0 ) { | |
this._waitCount--; | |
} else { | |
this.setMovementSuccess( true ); | |
var command = this._moveRoute.list[this._moveRouteIndex]; | |
if ( command ) { | |
this.processMoveCommand( command ); | |
this.advanceMoveRouteIndex(); | |
} | |
} | |
}; | |
Game_Character.prototype.moveRandom = function() { | |
if ( this._moveTarget ) { | |
return; | |
} | |
var d = 1 + Math.randomInt( 8 ); | |
var vx = Direction.isLeft( d ) ? -1 : ( Direction.isRight( d ) ? 1 : 0 ); | |
var vy = Direction.isUp( d ) ? -1 : ( Direction.isDown( d ) ? 1 : 0 ); | |
this.setDirectionVector( vx, vy ); | |
this._moveTarget = true; | |
this._moveTargetSkippable = true; | |
this._moveTargetX = Math.round( this.x + vx ); | |
this._moveTargetY = Math.round( this.y + vy ); | |
}; | |
Game_Character.prototype.moveTowardCharacter = function( character ) { | |
var vx = character.x - this.x; | |
var vy = character.y - this.y; | |
var length = Math.sqrt( vx * vx + vy * vy ); | |
if ( length > this.stepDistance ) { | |
this.setDirectionVector( vx, vy ); | |
vx /= length; | |
vy /= length; | |
this._moveTarget = true; | |
this._moveTargetSkippable = true; | |
this._moveTargetX = Math.round( this.x + vx ); | |
this._moveTargetY = Math.round( this.y + vy ); | |
} | |
}; | |
Game_Character.prototype.moveAwayFromCharacter = function( character ) { | |
var vx = character.x - this.x; | |
var vy = character.y - this.y; | |
var length = Math.sqrt( vx * vx + vy * vy ); | |
this.setDirectionVector( -vx, -vy ); | |
vx /= length; | |
vy /= length; | |
this._moveTarget = true; | |
this._moveTargetSkippable = true; | |
this._moveTargetX = Math.round( this.x - vx ); | |
this._moveTargetY = Math.round( this.y - vy ); | |
}; | |
var Game_Character_processMoveCommand = Game_Character.prototype.processMoveCommand; | |
Game_Character.prototype.processMoveCommand = function( command ) { | |
var gc = Game_Character; | |
var params = command.parameters; | |
switch ( command.code ) { | |
case gc.ROUTE_MOVE_DOWN: | |
this._moveTarget = true; | |
this._moveTargetX = ( this._x ); | |
this._moveTargetY = ( this._y + 1 ); | |
break; | |
case gc.ROUTE_MOVE_LEFT: | |
this._moveTarget = true; | |
this._moveTargetX = ( this._x - 1 ); | |
this._moveTargetY = ( this._y ); | |
break; | |
case gc.ROUTE_MOVE_RIGHT: | |
this._moveTarget = true; | |
this._moveTargetX = ( this._x + 1 ); | |
this._moveTargetY = ( this._y ); | |
break; | |
case gc.ROUTE_MOVE_UP: | |
this._moveTarget = true; | |
this._moveTargetX = ( this._x ); | |
this._moveTargetY = ( this._y - 1 ); | |
break; | |
case gc.ROUTE_MOVE_LOWER_L: | |
this._moveTarget = true; | |
this._moveTargetX = ( this._x - 1 ); | |
this._moveTargetY = ( this._y + 1 ); | |
break; | |
case gc.ROUTE_MOVE_LOWER_R: | |
this._moveTarget = true; | |
this._moveTargetX = ( this._x + 1 ); | |
this._moveTargetY = ( this._y + 1 ); | |
break; | |
case gc.ROUTE_MOVE_UPPER_L: | |
this._moveTarget = true; | |
this._moveTargetX = ( this._x - 1 ); | |
this._moveTargetY = ( this._y - 1 ); | |
break; | |
case gc.ROUTE_MOVE_UPPER_R: | |
this._moveTarget = true; | |
this._moveTargetX = ( this._x + 1 ); | |
this._moveTargetY = ( this._y - 1 ); | |
break; | |
case gc.ROUTE_MOVE_FORWARD: | |
this._wasDirectionFixed = this.isDirectionFixed(); | |
this.setDirectionFix( true ); | |
var vx = Direction.isLeft( this._direction ) ? -1 : ( Direction.isRight( this._direction ) ? 1 : 0 ); | |
var vy = Direction.isUp( this._direction ) ? -1 : ( Direction.isDown( this._direction ) ? 1 : 0 ); | |
this._moveTarget = true; | |
this._moveTargetX = ( this._x + vx ); | |
this._moveTargetY = ( this._y + vy ); | |
break; | |
case gc.ROUTE_MOVE_BACKWARD: | |
this._wasDirectionFixed = this.isDirectionFixed(); | |
this.setDirectionFix( true ); | |
var vx = Direction.isLeft( this._direction ) ? -1 : ( Direction.isRight( this._direction ) ? 1 : 0 ); | |
var vy = Direction.isUp( this._direction ) ? -1 : ( Direction.isDown( this._direction ) ? 1 : 0 ); | |
this._moveTarget = true; | |
this._moveTargetX = ( this._x - vx ); | |
this._moveTargetY = ( this._y - vy ); | |
break; | |
default: | |
Game_Character_processMoveCommand.call( this, command ); | |
break; | |
} | |
if ( $gameSystem._staticMoveAlignGrid !== MOVE_ROUTE.ALIGN_GRID ) { | |
$gameSystem._staticMoveAlignGrid = MOVE_ROUTE.ALIGN_GRID; | |
$gameSystem._moveAlignGrid = MOVE_ROUTE.ALIGN_GRID; | |
} | |
if ( this._moveTarget && $gameSystem._moveAlignGrid ) { | |
this._moveTargetX = Math.round( this._moveTargetX ); | |
this._moveTargetY = Math.round( this._moveTargetY ); | |
} | |
}; | |
} )(); | |
} )(); | |
/** | |
* Game_Player | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
var Game_Player_initMembers = Game_Player.prototype.initMembers; | |
Game_Player.prototype.initMembers = function() { | |
Game_Player_initMembers.call(this); | |
this._collider = Collider.createFromXML( PLAYER.COLLIDER_LIST ); | |
this._circularMovement = PLAYER.CIRCULAR_MOVEMENT; | |
}; | |
Game_Player.prototype.checkEventTriggerTouch = Game_CharacterBase.prototype.checkEventTriggerTouch; | |
var Game_Player_encounterProgressValue = Game_Player.prototype.encounterProgressValue; | |
Game_Player.prototype.encounterProgressValue = function() { | |
return this.stepDistance * Game_Player_encounterProgressValue.call( this ); | |
}; | |
var Game_Player_clearTransferInfo = Game_Player.prototype.clearTransferInfo; | |
Game_Player.prototype.clearTransferInfo = function() { | |
Game_Player_clearTransferInfo.call( this ); | |
this._moveTarget = false; | |
this._moveTargetSkippable = false; | |
}; | |
Game_Player.prototype.update = function( sceneActive ) { | |
var lastScrolledX = this.scrolledX(); | |
var lastScrolledY = this.scrolledY(); | |
var wasMoving = this._wasMoving; | |
this.updateDashing(); | |
if ( sceneActive ) { | |
this.moveByInput(); | |
} | |
Game_Character.prototype.update.call( this ); | |
this.updateScroll( lastScrolledX, lastScrolledY ); | |
this.updateVehicle(); | |
if ( !this._isMoving ) { | |
this.updateNonmoving( wasMoving, sceneActive ); | |
} | |
this._followers.update(); | |
}; | |
Game_Player.prototype.getInputDirection = function() { | |
return Input.dir8; | |
}; | |
Game_Player.prototype.moveByInput = function() { | |
if ( $gameSystem._staticEnableTouchMouse != INPUT_CONFIG.ENABLE_TOUCH_MOUSE ) { | |
$gameSystem._staticEnableTouchMouse = INPUT_CONFIG.ENABLE_TOUCH_MOUSE; | |
$gameSystem._enableTouchMouse = INPUT_CONFIG.ENABLE_TOUCH_MOUSE; | |
} | |
if ( this._moveTarget ) { | |
this._touchTarget = null; | |
} | |
if ( !this.isMoving() && this.canMove() ) { | |
if ( navigator.getGamepads ) { | |
// Gamepad movement | |
var gamepads = navigator.getGamepads(); | |
var didMove = false; | |
var didTurn = false; | |
if ( gamepads ) { | |
for ( var ii = 0; ii < gamepads.length; ii++ ) { | |
var gamepad = gamepads[ii]; | |
if ( gamepad && gamepad.connected ) { | |
if ( !didMove ) { | |
if ( INPUT_CONFIG.GAMEPAD_MODE & 0x2 ) { | |
var vy = gamepad.axes[1]; | |
var vx = gamepad.axes[0]; | |
var length = Math.sqrt( vy * vy + vx * vx ); | |
if ( length > GAME_PAD_THRESHOLD ) { | |
if ( length - GAME_PAD_THRESHOLD > GAME_PAD_LIMIT ) { | |
vx /= length; | |
vy /= length; | |
} | |
if ( this._circularMovement ) { | |
this.moveVector( vx * this.stepDistance, vy * this.stepDistance ); | |
} else { | |
var vector = Direction.normalizeSquare( vx, vy ); | |
this.moveVector( vector.x * this.stepDistance, vector.y * this.stepDistance ); | |
} | |
didMove = true; | |
} | |
} else { | |
didMove = true; | |
} | |
} | |
if ( !didTurn && ( INPUT_CONFIG.GAMEPAD_MODE & 0x1 ) ) { | |
var vy = gamepad.axes[3]; | |
var vx = gamepad.axes[2]; | |
var length = Math.sqrt( vy * vy + vx * vx ); | |
if ( length > GAME_PAD_THRESHOLD ) { | |
this.setDirectionVector( vx, vy ); | |
didTurn = true; | |
} | |
} | |
} | |
} | |
} | |
if ( didMove ) { | |
this._touchTarget = null; | |
return; | |
} | |
} | |
var direction = this.getInputDirection(); | |
if ( direction > 0 ) { | |
// Regular movement | |
this.executeMove( direction ); | |
this._touchTarget = null; | |
} else if ( $gameSystem._enableTouchMouse && $gameTemp.isDestinationValid() ) { | |
// Touch movement | |
var characterTarget = null; | |
var touchedCharacters = $gameMap.getCharactersUnderPoint( $gameTemp.destinationX(), $gameTemp.destinationY() ).filter( function( character ) { | |
// Filter out events that player cannot reach | |
return !( character._eventId && !character.isNormalPriority() ); | |
} ); | |
if ( this.isInVehicle() ) { | |
// In vehicle | |
if ( touchedCharacters.contains( $gamePlayer.vehicle() ) ) { | |
// Get off vehicle | |
this.getOffVehicle(); | |
} | |
} else { | |
// Check if we're touching an interactable | |
if ( touchedCharacters.contains( $gameMap.airship() ) && $gameMap.airship()._mapId === $gameMap.mapId() ) { | |
characterTarget = $gameMap.airship(); | |
} else if ( touchedCharacters.contains( $gameMap.ship() ) && $gameMap.ship()._mapId === $gameMap.mapId() ) { | |
characterTarget = $gameMap.ship(); | |
} else if ( touchedCharacters.contains( $gameMap.boat() ) && $gameMap.boat()._mapId === $gameMap.mapId() ) { | |
characterTarget = $gameMap.boat(); | |
} else if ( touchedCharacters.length === 1 && touchedCharacters[0] === $gamePlayer ) { | |
// Only touched player, action time | |
if ( !this.getOnVehicle() ) { | |
this.checkEventTriggerHere( [0] ); | |
} | |
characterTarget = $gamePlayer; | |
} else if ( this.canStartLocalEvents() ) { | |
// Only care about events now | |
touchedCharacters = touchedCharacters.filter( function( character ) { | |
return !!character._eventId && character._trigger === 0; | |
} ); | |
if ( touchedCharacters.length ) { | |
// Move toward character | |
characterTarget = touchedCharacters[0]; | |
} | |
} | |
} | |
// Move toward destination | |
if ( !characterTarget ) { | |
this._touchTarget = new Point( $gameTemp.destinationX() - 0.5, $gameTemp.destinationY() - 0.5 ); | |
} else { | |
this._touchTarget = characterTarget; | |
} | |
$gameTemp.clearDestination(); | |
} | |
if ( this._touchTarget ) { | |
var dx = $gameMap.directionX( this._x, this._touchTarget.x ); | |
var dy = $gameMap.directionY( this._y, this._touchTarget.y ); | |
var length = Math.sqrt( dx * dx + dy * dy ); | |
if ( length <= this.stepDistance ) { | |
this._touchTarget = null; | |
} else { | |
dx /= length; | |
dy /= length; | |
if ( this._circularMovement ) { | |
this.moveVector( dx * this.stepDistance, dy * this.stepDistance ); | |
} else { | |
var vector = Direction.normalizeSquare( dx, dy ); | |
this.moveVector( vector.x * this.stepDistance, vector.y * this.stepDistance ); | |
} | |
if ( Math.abs( dx ) > Math.abs( dy ) ) { | |
this.setDirectionVector( dx, 0 ); | |
} else { | |
this.setDirectionVector( 0, dy ); | |
} | |
if ( this.isOnLadder() ) { | |
this.setDirection( 8 ); | |
} | |
// Can't move any more, so stop walking | |
if ( !this.isMovementSucceeded() ) { | |
var collider = this._touchTarget.collider ? this._touchTarget.collider() : null; | |
if ( collider ) { | |
// Touching a character, check if we've reached it | |
var rx = dx * this.stepDistance; | |
var ry = dy * this.stepDistance; | |
if ( Collider.intersect( this._touchTarget.x, this._touchTarget.y, collider, this._x + rx, this._y + ry, this.collider() ) ) { | |
var vehicle; | |
if ( !!this._touchTarget._eventId ) { | |
this._touchTarget.start(); | |
} else if ( this._touchTarget === $gameMap.airship() ) { | |
vehicle = $gameMap.airship(); | |
this._vehicleType = 'airship'; | |
this._collisionType = CollisionMesh.AIRSHIP; | |
} else if ( this._touchTarget === $gameMap.ship() ) { | |
vehicle = $gameMap.ship(); | |
this._vehicleType = 'ship'; | |
this._collisionType = CollisionMesh.SHIP; | |
} else if ( this._touchTarget === $gameMap.boat() ) { | |
vehicle = $gameMap.boat(); | |
this._vehicleType = 'boat'; | |
this._collisionType = CollisionMesh.BOAT; | |
} | |
if ( vehicle ) { | |
this._vehicleGettingOn = true; | |
vehicle._passengerCollider = this.collider(); | |
this._collider = vehicle.collider(); | |
var dx = $gameMap.directionX( this._x, vehicle._x ); | |
var dy = $gameMap.directionY( this._y, vehicle._y ); | |
var wasThrough = this.isThrough(); | |
this.setThrough( true ); | |
this.moveVector( dx, dy ); | |
this.setThrough( wasThrough ); | |
this.gatherFollowers(); | |
} | |
} else if ( !!this._touchTarget ) { | |
// Check if our target can only be reached by action | |
if ( !this.getOnVehicle() ) { | |
this.checkEventTriggerThere( [0] ); | |
} | |
} | |
} | |
this._touchTarget = null; | |
} | |
} | |
} | |
} | |
}; | |
Game_Player.prototype.checkEventTriggerHere = function( triggers ) { | |
if ( this.canStartLocalEvents() ) { | |
var collider = this.collider(); | |
var bboxTests = $gameMap.getAABBoxTests( this ); | |
var player = this; | |
var vx = Direction.isLeft( this._direction ) ? -this.stepDistance : ( Direction.isRight( this._direction ) ? this.stepDistance : 0 ); | |
var vy = Direction.isUp( this._direction ) ? -this.stepDistance : ( Direction.isDown( this._direction ) ? this.stepDistance : 0 ); | |
// Gather any solid characters within the "here" bounding box | |
var loopMap = {}; | |
var events = $gameMap.events().filter( function( event ) { | |
for ( var ii = 0; ii < bboxTests.length; ii++ ) { | |
if ( event.isTriggerIn( triggers ) ) { | |
if ( event.isNormalPriority() ) { | |
if ( Collider.aabboxCheck( bboxTests[ii].x + vx, bboxTests[ii].y + vy, bboxTests[ii].aabbox, event._x, event._y, event.collider().aabbox ) ) { | |
loopMap[event] = bboxTests[ii].type; | |
return true; | |
} | |
} else { | |
if ( Collider.aabboxCheck( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, event._x, event._y, event.collider().aabbox ) ) { | |
loopMap[event] = bboxTests[ii].type; | |
return true; | |
} | |
} | |
} | |
} | |
return false; | |
} ); | |
// Test collision with characters | |
for ( var ii = 0; ii < events.length; ii++ ) { | |
var entryX = events[ii]._x; | |
var entryY = events[ii]._y; | |
if ( loopMap[events[ii]] == 1 ) { entryX += $gameMap.width(); } | |
else if ( loopMap[events[ii]] == 2 ) { entryX -= $gameMap.width(); } | |
else if ( loopMap[events[ii]] == 3 ) { entryY += $gameMap.height(); } | |
else if ( loopMap[events[ii]] == 4 ) { entryY -= $gameMap.height(); } | |
else if ( loopMap[events[ii]] == 5 ) { entryX += $gameMap.width(); entryY += $gameMap.height(); } | |
else if ( loopMap[events[ii]] == 6 ) { entryX -= $gameMap.width(); entryY += $gameMap.height(); } | |
else if ( loopMap[events[ii]] == 7 ) { entryX += $gameMap.width(); entryY -= $gameMap.height(); } | |
else if ( loopMap[events[ii]] == 8 ) { entryX -= $gameMap.width(); entryY -= $gameMap.height(); } | |
if ( events[ii].isNormalPriority() && Collider.intersect( this._x + vx, this._y + vy, collider, entryX, entryY, events[ii].collider() ) ) { | |
// Normal priority player-touch/event-touch | |
events[ii].start(); | |
} else if ( events[ii]._trigger === 2 ) { | |
// Event touch is encasing | |
if ( Collider.encase( entryX, entryY, events[ii].collider(), this._x, this._y, collider ) || Collider.encase( this._x, this._y, collider, entryX, entryY, events[ii].collider() ) ) { | |
events[ii].start(); | |
} | |
} else if ( Collider.intersect( this._x, this._y, collider, entryX, entryY, events[ii].collider() ) ) { | |
events[ii].start(); | |
} | |
} | |
} | |
}; | |
Game_Player.prototype.checkEventTriggerThere = function( triggers ) { | |
if ( this.canStartLocalEvents() ) { | |
var vx = Direction.isLeft( this._direction ) ? -this.actionWidth() : ( Direction.isRight( this._direction ) ? this.actionWidth() : 0 ); | |
var vy = Direction.isUp( this._direction ) ? -this.actionHeight() : ( Direction.isDown( this._direction ) ? this.actionHeight() : 0 ); | |
var collider = this.collider(); | |
var bboxTests = $gameMap.getAABBoxTests( this, vx, vy ); | |
var player = this; | |
// Gather any solid characters within the "there" bounding box | |
var loopMap = {}; | |
var events = $gameMap.events().filter( function( event ) { | |
for ( var ii = 0; ii < bboxTests.length; ii++ ) { | |
if ( event.isTriggerIn( triggers ) && event.isNormalPriority() && Collider.aabboxCheck( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, event._x, event._y, event.collider().aabbox ) ) { | |
loopMap[event] = bboxTests[ii].type; | |
return true; | |
} | |
} | |
return false; | |
} ); | |
// Test collision with characters | |
for ( var ii = 0; ii < events.length; ii++ ) { | |
var entryX = events[ii]._x; | |
var entryY = events[ii]._y; | |
if ( loopMap[events[ii]] == 1 ) { entryX += $gameMap.width(); } | |
else if ( loopMap[events[ii]] == 2 ) { entryX -= $gameMap.width(); } | |
else if ( loopMap[events[ii]] == 3 ) { entryY += $gameMap.height(); } | |
else if ( loopMap[events[ii]] == 4 ) { entryY -= $gameMap.height(); } | |
else if ( loopMap[events[ii]] == 5 ) { entryX += $gameMap.width(); entryY += $gameMap.height(); } | |
else if ( loopMap[events[ii]] == 6 ) { entryX -= $gameMap.width(); entryY += $gameMap.height(); } | |
else if ( loopMap[events[ii]] == 7 ) { entryX += $gameMap.width(); entryY -= $gameMap.height(); } | |
else if ( loopMap[events[ii]] == 8 ) { entryX -= $gameMap.width(); entryY -= $gameMap.height(); } | |
if ( events[ii]._trigger === 2 ) { | |
// Event touch is encasing | |
if ( Collider.encase( this._x + vx, this._y + vy, collider, entryX, entryY, events[ii].collider() ) || Collider.encase( entryX, entryY, events[ii].collider(), this._x + vx, this._y + vy, collider ) ) { | |
events[ii].start(); | |
} | |
} else if ( Collider.intersect( this._x + vx, this._y + vy, collider, entryX, entryY, events[ii].collider() ) ) { | |
events[ii].start(); | |
} | |
} | |
if ( !$gameMap.isAnyEventStarting() ) { | |
// Check for counters | |
var events = []; | |
var tiles = $gameMap.getTilesUnder( this, vx, vy ); | |
for ( var ii = 0; ii < tiles.length; ii++ ) { | |
if ( $gameMap.isCounter( tiles[ii][0], tiles[ii][1] ) ) { | |
var x3 = $gameMap.roundXWithDirection( tiles[ii][0], this._direction ); | |
var y3 = $gameMap.roundYWithDirection( tiles[ii][1], this._direction ); | |
// Gather any solid characters within the "over counter" bounding box | |
events = events.concat( $gameMap.events().filter( function( event ) { | |
if ( event.isTriggerIn( triggers ) && event.isNormalPriority() && Collider.aabboxCheck( x3, y3, Collider.sharedTile().aabbox, event._x, event._y, event.collider().aabbox ) ) { | |
return true; | |
} | |
return false; | |
} ) ); | |
} | |
} | |
if ( events.length === 0 ) { | |
return; | |
} | |
var closest; | |
var dist = Number.POSITIVE_INFINITY; | |
for ( var ii = 0; ii < events.length; ii++ ) { | |
var entryX = events[ii]._x; | |
var entryY = events[ii]._y; | |
var dx = this._x - entryX; | |
var dy = this._y - entryY; | |
var td = ( dx * dx + dy * dy ); | |
if ( td < dist ) { | |
dist = td; | |
closest = events[ii]; | |
} | |
} | |
closest.start(); | |
} | |
} | |
}; | |
Game_Player.prototype.startMapEvent = function( x, y, triggers, normal ) { | |
if ( !$gameMap.isEventRunning() ) { | |
$gameMap.eventsXy( x, y ).forEach( function( event ) { | |
if ( event.isTriggerIn( triggers ) && event.isNormalPriority() === normal ) { | |
event.start(); | |
} | |
} ); | |
} | |
}; | |
Game_Player.prototype.moveStraight = function( d ) { | |
Game_Character.prototype.moveStraight.call( this, d ); | |
}; | |
Game_Player.prototype.moveDiagonally = function( horz, vert ) { | |
Game_Character.prototype.moveDiagonally.call( this, horz, vert ); | |
}; | |
Game_Player.prototype.getOnVehicle = function() { | |
var vx = Direction.isLeft( this._direction ) ? -0.5 : ( Direction.isRight( this._direction ) ? 0.5 : 0 ); | |
var vy = Direction.isUp( this._direction ) ? -0.5 : ( Direction.isDown( this._direction ) ? 0.5 : 0 ); | |
var bboxTests = $gameMap.getAABBoxTests( this, vx, vy ); | |
var vehicle; | |
var airship = $gameMap.airship(); | |
var ship = $gameMap.ship(); | |
var boat = $gameMap.boat(); | |
for ( var ii = 0; ii < bboxTests.length; ii++ ) { | |
if ( !!airship && airship._mapId === $gameMap.mapId() && Collider.aabboxCheck( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, airship._x, airship._y, airship.collider().aabbox ) ) { | |
this._vehicleType = 'airship'; | |
this._collisionType = CollisionMesh.AIRSHIP; | |
vehicle = airship; | |
break; | |
} | |
if ( !!ship && ship._mapId === $gameMap.mapId() && Collider.aabboxCheck( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, ship._x, ship._y, ship.collider().aabbox ) ) { | |
this._vehicleType = 'ship'; | |
this._collisionType = CollisionMesh.SHIP; | |
vehicle = ship; | |
break; | |
} | |
if ( !!boat && boat._mapId === $gameMap.mapId() && Collider.aabboxCheck( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, boat._x, boat._y, boat.collider().aabbox ) ) { | |
this._vehicleType = 'boat'; | |
this._collisionType = CollisionMesh.BOAT; | |
vehicle = boat; | |
break; | |
} | |
} | |
if ( this.isInVehicle() ) { | |
this._vehicleGettingOn = true; | |
vehicle._passengerCollider = this.collider(); | |
this._collider = vehicle.collider(); | |
var dx = $gameMap.directionX( this._x, vehicle._x ); | |
var dy = $gameMap.directionY( this._y, vehicle._y ); | |
var wasThrough = this.isThrough(); | |
this.setThrough( true ); | |
this.moveVector( dx, dy ); | |
this.setThrough( wasThrough ); | |
this.gatherFollowers(); | |
} | |
return this._vehicleGettingOn; | |
}; | |
Game_Player.prototype.getOffVehicle = function() { | |
if ( this.vehicle().isLandOk( this.x, this.y, this.direction() ) ) { | |
if ( this.isInAirship() ) { | |
this.setDirection( 2 ); | |
} | |
var vhx = this.vehicle().x; | |
var vhy = this.vehicle().y; | |
var vhd = this.vehicle().direction(); | |
for (const follower of this._followers._data) { | |
follower._x = vhx; | |
follower._y = vhy; | |
follower._realX = vhx; | |
follower._realY = vhy; | |
follower.setDirection( vhd ); | |
} | |
// this._followers.synchronize( this.vehicle().x, this.vehicle().y, this.vehicle().direction() ); | |
this.vehicle().getOff(); | |
if ( !this.isInAirship() ) { | |
var vehicleBox = this.vehicle().collider().aabbox; | |
var passengerBox = this.vehicle()._passengerCollider.aabbox; | |
var d = this.direction(); | |
// Get disembark direction | |
var vx; | |
if ( Direction.isLeft( d ) ) { | |
vx = Math.floor( ( -passengerBox.right + vehicleBox.left ) * 64 ) / 64; | |
} else if ( Direction.isRight( d ) ) { | |
vx = Math.ceil( ( vehicleBox.right - passengerBox.left ) * 64 ) / 64; | |
} else { | |
vx = 0; | |
} | |
var vy; | |
if ( Direction.isUp( d ) ) { | |
vy = Math.floor( ( -passengerBox.bottom + vehicleBox.top ) * 64 ) / 64; | |
} else if ( Direction.isDown( d ) ) { | |
vy = Math.ceil( ( vehicleBox.bottom - passengerBox.top ) * 64 ) / 64; | |
} else { | |
vy = 0; | |
} | |
this.setThrough( true ); | |
this.moveVector( vx, vy ); | |
this.setThrough( false ); | |
this.setTransparent( false ); | |
} | |
this._vehicleGettingOff = true; | |
this.setMoveSpeed( 4 ); | |
this.setThrough( false ); | |
this.makeEncounterCount(); | |
this.gatherFollowers(); | |
} | |
return this._vehicleGettingOff; | |
}; | |
Game_Player.prototype.updateVehicleGetOff = function() { | |
if ( !this.areFollowersGathering() && this.vehicle().isLowest() && this._collisionType !== CollisionMesh.WALK ) { | |
this._collider = this.vehicle()._passengerCollider; | |
this.vehicle()._passengerCollider = undefined; | |
this._collisionType = CollisionMesh.WALK; | |
this._vehicleGettingOff = false; | |
this._vehicleType = 'walk'; | |
this.setTransparent( false ); | |
} | |
}; | |
} )(); | |
/** | |
* Extensions | |
*/ | |
( function() { | |
Game_Player.prototype.actionWidth = function() { | |
var bbox = this.collider().aabbox; | |
var width = bbox.right - bbox.left; | |
return width < 1 ? width : 1; | |
}; | |
Game_Player.prototype.actionHeight = function() { | |
var bbox = this.collider().aabbox; | |
var height = bbox.bottom - bbox.top; | |
return height < 1 ? height : 1; | |
}; | |
} )(); | |
} )(); | |
/** | |
* Game_Follower | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
Game_Follower.prototype.initMembers = function() { | |
Game_Character.prototype.initMembers.call( this ); | |
this._collider = Collider.createFromXML( FOLLOWERS.COLLIDER_LIST ); | |
this._isFrozen = false; | |
this._circularMovement = FOLLOWERS.CIRCULAR_MOVEMENT; | |
}; | |
Game_Follower.prototype.chaseCharacter = function( character ) { | |
if ( this._moveTarget || this._isFrozen ) { | |
return; | |
} | |
var displayWidth = Graphics.width / $gameMap.tileWidth(); | |
var displayHeight = Graphics.height / $gameMap.tileHeight(); | |
var aabbox = this.collider().aabbox; | |
var width = aabbox.right - aabbox.left; | |
var height = aabbox.bottom - aabbox.top; | |
var ax = this._x + ( aabbox.left + aabbox.right ) / 2; | |
var ay = this._y + ( aabbox.top + aabbox.bottom ) / 2; | |
// Teleportation | |
var midX = $gameMap.canvasToMapX( Graphics.width / 2 ); | |
var dmX = $gameMap.directionX( ax, midX ); | |
if ( dmX > displayWidth + width ) { | |
// Off left edge | |
var tx = $gameMap.canvasToMapX( 0 ) - width; | |
if ( $gameMap.canWalk( this, tx, this._y ) ) { | |
this.setPosition( tx, this._y ); | |
} | |
} else if ( dmX < -displayWidth - width ) { | |
// Off right edge | |
var tx = $gameMap.canvasToMapX( Graphics.width ) + width; | |
if ( $gameMap.canWalk( this, tx, this._y ) ) { | |
this.setPosition( tx, this._y ); | |
} | |
} | |
var midY = $gameMap.canvasToMapY( Graphics.height / 2 ); | |
var dmY = $gameMap.directionY( ay, midY ); | |
if ( dmY > displayHeight + height ) { | |
// Off top edge | |
var ty = $gameMap.canvasToMapY( 0 ) - height; | |
if ( $gameMap.canWalk( this, this._x, ty ) ) { | |
this.setPosition( this._x, ty ); | |
} | |
} else if ( dmY < -displayHeight - height ) { | |
// Off bottom edge | |
var ty = $gameMap.canvasToMapY( Graphics.height ) + height; | |
if ( $gameMap.canWalk( this, this._x, ty ) ) { | |
this.setPosition( this._x, ty ); | |
} | |
} | |
var characterBox = character.collider().aabbox; | |
var cWidth = characterBox.right - characterBox.left; | |
var cHeight = characterBox.bottom - characterBox.top; | |
var bx = character._x + ( characterBox.left + characterBox.right ) / 2; | |
var by = character._y + ( characterBox.top + characterBox.bottom ) / 2; | |
var dx = $gameMap.directionX( ax, bx ); | |
var dy = $gameMap.directionY( ay, by ); | |
var distance = Math.sqrt( dx * dx + dy * dy ); | |
var radius = ( this.collider().type === Collider.CIRCLE ? this.collider().radius : ( width > height ? width : height ) / 2 ); | |
var characterRadius = ( character.collider().type === Collider.CIRCLE ? character.collider().radius : ( cWidth > cHeight ? cWidth : cHeight ) / 2 ); | |
if ( distance > ( radius + characterRadius ) * $gameSystem._followerDistance ) { | |
// Chase if far away | |
this.setMoveSpeed( character.realMoveSpeed() ); | |
this.setThrough( $gamePlayer.isThrough() || $gamePlayer.isDebugThrough() ); | |
if ( distance > 2 ) { | |
dx /= distance; | |
dy /= distance; | |
} | |
if ( this._circularMovement ) { | |
this.moveVector( dx * this.stepDistance, dy * this.stepDistance ); | |
} else { | |
var vector = Direction.normalizeSquare( dx, dy ); | |
this.moveVector( vector.x * this.stepDistance, vector.y * this.stepDistance ); | |
} | |
this.setThrough( true ); | |
} | |
if ( this.isOnLadder() ) { | |
this.setDirection( 8 ); | |
} else if ( !this._wasMoving ) { | |
var adx = Math.abs( dx ); | |
var ady = Math.abs( dy ); | |
if ( adx > ady ) { | |
this.setDirectionVector( dx, 0 ); | |
} else if ( ady > adx ) { | |
this.setDirectionVector( 0, dy ); | |
} | |
} | |
}; | |
} )(); | |
/** | |
* Extensions | |
*/ | |
( function() { | |
Game_Follower.prototype.setFrozen = function( frozen ) { | |
this._isFrozen = frozen; | |
}; | |
} )(); | |
} )(); | |
/** | |
* Game_Followers | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
Game_Followers.prototype.update = function() { | |
if ( this.areGathering() ) { | |
var direction = $gamePlayer.direction(); | |
var visibleFollowers = this.visibleFollowers(); | |
for ( var ii = 0; ii < visibleFollowers.length; ii++ ) { | |
var follower = visibleFollowers[ii]; | |
var dx = $gameMap.directionX( follower._x, this._targetX ); | |
var dy = $gameMap.directionY( follower._y, this._targetY ); | |
var distance = Math.sqrt( dx * dx + dy * dy ); | |
dx /= distance; | |
dy /= distance; | |
follower.setThrough( true ); | |
follower.moveVector( dx * follower.stepDistance, dy * follower.stepDistance ); | |
follower.setThrough( false ); | |
follower.setDirection( direction ); | |
} | |
if ( this.areGathered() ) { | |
this._gathering = false; | |
} | |
} else { | |
this.updateMove(); | |
} | |
this.visibleFollowers().forEach( function( follower ) { | |
follower.update(); | |
}, this ); | |
if ( $gameSystem._staticFollowerDistance != FOLLOWERS.DISTANCE ) { | |
$gameSystem._staticFollowerDistance = FOLLOWERS.DISTANCE; | |
$gameSystem._followerDistance = FOLLOWERS.DISTANCE; | |
} | |
}; | |
Game_Followers.prototype.gather = function() { | |
this._gathering = true; | |
this._targetX = $gamePlayer._x; | |
this._targetY = $gamePlayer._y; | |
}; | |
Game_Followers.prototype.areGathered = function() { | |
var screenRadius = Math.sqrt( Graphics.width * Graphics.width + Graphics.height * Graphics.height ) / 2; | |
screenRadius /= Math.sqrt( $gameMap.tileWidth() * $gameMap.tileWidth() + $gameMap.tileHeight() * $gameMap.tileHeight() ) / 2; | |
var visibleFollowers = this.visibleFollowers(); | |
for ( var ii = 0; ii < visibleFollowers.length; ii++ ) { | |
var follower = visibleFollowers[ii]; | |
var dx = $gameMap.directionX( follower._realX, this._targetX ); | |
var dy = $gameMap.directionY( follower._realY, this._targetY ); | |
var distance = Math.sqrt( dx * dx + dy * dy ); | |
if ( distance > screenRadius ) { | |
// Don't count if off screen | |
continue; | |
} else if ( distance > follower.stepDistance ) { | |
return false; | |
} else { | |
follower._x = this._targetX; | |
follower._y = this._targetY; | |
follower._realX = this._targetX; | |
follower._realY = this._targetY; | |
} | |
} | |
return true; | |
}; | |
} )(); | |
/** | |
* Extensions | |
*/ | |
( function() { | |
Game_Followers.prototype.contains = function( item ) { | |
return this._data.indexOf( item ) >= 0; | |
}; | |
} )(); | |
} )(); | |
/** | |
* Game_Vehicle | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
var Game_Vehicle_initialize = Game_Vehicle.prototype.initialize; | |
Game_Vehicle.prototype.initialize = function( type ) { | |
Game_Vehicle_initialize.call( this, type ); | |
if ( this.isAirship() ) { | |
this._collider = Collider.createFromXML( VEHICLES.AIRSHIP_COLLIDER_LIST ); | |
} else if ( this.isShip() ) { | |
this._collider = Collider.createFromXML( VEHICLES.SHIP_COLLIDER_LIST ); | |
} else if ( this.isBoat() ) { | |
this._collider = Collider.createFromXML( VEHICLES.BOAT_COLLIDER_LIST ); | |
} else { | |
this._collider = Collider.sharedCharacter(); | |
} | |
}; | |
Game_Vehicle.prototype.isLandOk = function( x, y, d ) { | |
if ( this.isAirship() ) { | |
$gamePlayer._collider = this._passengerCollider; // Reset colliders temporarily | |
// Check rough tiles under colliders | |
var tiles = $gameMap.getTilesUnder( this ).concat( $gameMap.getTilesUnder( $gamePlayer ) ); | |
var canWalk = true; | |
for ( var ii = 0; ii < tiles.length; ii++ ) { | |
if ( !$gameMap.isAirshipLandOk( tiles[ii][0], tiles[ii][1] ) ) { | |
canWalk = false; | |
break; | |
} | |
} | |
if ( canWalk && ( $gameMap.touchesCharacters( this, x, y ) || $gameMap.touchesCharacters( $gamePlayer, x, y ) ) ) { | |
canWalk = false; | |
} | |
$gamePlayer._collider = this.collider(); // Undo player collider reset | |
return canWalk; | |
} else { | |
var vehicleBox = this.collider().aabbox; | |
var passengerBox = this._passengerCollider.aabbox; | |
// Get disembark direction | |
var tw = $gameMap.tileWidth(); | |
var th = $gameMap.tileHeight(); | |
var vx; | |
if ( Direction.isLeft( d ) ) { | |
vx = Math.floor( ( -passengerBox.right + vehicleBox.left ) * 64 ) / 64; | |
} else if ( Direction.isRight( d ) ) { | |
vx = Math.ceil( ( vehicleBox.right - passengerBox.left ) * 64 ) / 64; | |
} else { | |
vx = 0; | |
} | |
var vy; | |
if ( Direction.isUp( d ) ) { | |
vy = Math.floor( ( -passengerBox.bottom + vehicleBox.top ) * 64 ) / 64; | |
} else if ( Direction.isDown( d ) ) { | |
vy = Math.ceil( ( vehicleBox.bottom - passengerBox.top ) * 64 ) / 64; | |
} else { | |
vy = 0; | |
} | |
var reverseDirection = this.reverseDir( d ); | |
$gamePlayer._collider = this._passengerCollider; // Reset colliders temporarily | |
// Check rough tiles under player | |
var tiles = $gameMap.getTilesUnder( $gamePlayer, vx, vy ); | |
var canWalk = true; | |
for ( var ii = 0; ii < tiles.length; ii++ ) { | |
if ( !$gameMap.isAABBoxValid( tiles[ii][0], tiles[ii][1], vehicleBox ) || !$gameMap.isAABBoxValid( tiles[ii][0], tiles[ii][1], passengerBox ) ) { | |
canWalk = false; | |
break; | |
} else if ( !$gameMap.isPassable( tiles[ii][0], tiles[ii][1], reverseDirection ) ) { | |
canWalk = false; | |
break; | |
} | |
} | |
if ( canWalk && $gameMap.touchesCharacters( $gamePlayer, x + vx, y + vy ) ) { | |
canWalk = false; | |
} | |
$gamePlayer._collider = this.collider(); // Undo player collider reset | |
return canWalk; | |
} | |
}; | |
} )(); | |
} )(); | |
/** | |
* Game_Event | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
var Game_Event_setupPageSettings = Game_Event.prototype.setupPageSettings; | |
Game_Event.prototype.setupPageSettings = function() { | |
Game_Event_setupPageSettings.call( this ); | |
this.collider(); | |
}; | |
var Game_Event_start = Game_Event.prototype.start; | |
Game_Event.prototype.start = function() { | |
if ( this._lastFrame === Graphics.frameCount ) { | |
return; | |
} | |
Game_Event_start.call( this ); | |
this._lastFrame = Graphics.frameCount + 1; | |
}; | |
Game_Event.prototype.collider = function() { | |
var page = this.page(); | |
if ( !!page ) { | |
if ( !page._collider ) { | |
var mapId = $gameMap.mapId(); | |
var storedCollider = $gameSystem._eventColliders[mapId] ? $gameSystem._eventColliders[mapId][this.eventId()] : undefined; | |
if ( !!storedCollider ) { | |
page._collider = storedCollider; | |
} | |
} | |
if ( !page._collider ) { | |
var comments = []; | |
for ( var ii = 0; ii < page.list.length; ii++ ) { | |
if ( page.list[ii].code === 108 || page.list[ii].code === 408 ) { | |
comments.push( page.list[ii].parameters[0] ); | |
} | |
} | |
if ( comments.length > 0 ) { | |
var xmlDoc = DOM_PARSER.parseFromString( '<doc>' + comments.join( '\n' ) + '</doc>', 'text/xml' ); | |
var childNodes = xmlDoc.childNodes[0].childNodes; | |
for ( var ii = 0; ii < childNodes.length; ii++ ) { | |
if ( childNodes[ii].nodeName === 'collider' ) { | |
var collider = Collider.createFromXML( xmlDoc.childNodes[0] ); | |
if ( collider === Collider.null() ) { | |
var childChilds = childNodes[ii].childNodes; | |
for ( var jj = 0; jj < childChilds.length; jj++ ) { | |
if ( childChilds[jj].nodeName === 'preset' ) { | |
page._collider = Collider.getPreset( childChilds[jj].innerHTML.trim() ); | |
break; | |
} | |
} | |
} else { | |
page._collider = collider; | |
} | |
break; | |
} | |
} | |
} | |
} | |
if ( !page._collider ) { | |
var dataEvent = $dataMap.events[this.eventId()]; | |
var presetId = dataEvent ? dataEvent.meta.collider : null; | |
if ( presetId ) { | |
var asNum = +presetId; | |
if ( isNaN( asNum ) ) { | |
page._collider = Collider.getPreset( presetId.trim() ); | |
} else { | |
page._collider = Collider.getPreset( asNum ); | |
} | |
} | |
} | |
this._hasCustomCollider = !!page._collider; | |
if ( !page._collider ) { | |
if ( this.isTile() || !this.characterName() || this.isObjectCharacter() ) { | |
page._collider = Collider.createFromXML( EVENT.TILE_COLLIDER_LIST ); | |
} else { | |
page._collider = Collider.createFromXML( EVENT.CHARACTER_COLLIDER_LIST ); | |
} | |
} | |
return page._collider; | |
} | |
return Collider.null(); | |
}; | |
Game_Event.prototype.setCollider = function( collider ) { | |
var pages = this.event().pages; | |
for ( var ii = 0; ii < pages.length; ii++ ) { | |
pages[ii]._collider = collider; | |
} | |
$gameSystem._eventColliders[$gameMap.mapId()][this.eventId()] = collider; | |
}; | |
Game_Event.prototype.checkEventTriggerTouch = function( x, y ) { | |
if ( this._trigger === 2 && !$gameMap.isEventRunning() && !this.isJumping() && this.isNormalPriority() ) { | |
var bboxTests = $gameMap.getAABBoxTests( this, x - this._x, y - this._y ); | |
var loopMap = -1; | |
for ( var ii = 0; ii < bboxTests.length; ii++ ) { | |
if ( Collider.aabboxCheck( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, $gamePlayer._x, $gamePlayer._y, $gamePlayer.collider().aabbox ) ) { | |
loopMap = bboxTests[ii].type; | |
break; | |
} | |
} | |
if ( loopMap < 0 ) { | |
return; | |
} | |
var playerX = $gamePlayer._x; | |
var playerY = $gamePlayer._y; | |
if ( loopMap == 1 ) { playerX += $gameMap.width(); } | |
else if ( loopMap == 2 ) { playerX -= $gameMap.width(); } | |
else if ( loopMap == 3 ) { playerY += $gameMap.height(); } | |
else if ( loopMap == 4 ) { playerY -= $gameMap.height(); } | |
else if ( loopMap == 5 ) { playerX += $gameMap.width(); playerY += $gameMap.height(); } | |
else if ( loopMap == 6 ) { playerX -= $gameMap.width(); playerY += $gameMap.height(); } | |
else if ( loopMap == 7 ) { playerX += $gameMap.width(); playerY -= $gameMap.height(); } | |
else if ( loopMap == 8 ) { playerX -= $gameMap.width(); playerY -= $gameMap.height(); } | |
if ( Collider.intersect( x, y, this.collider(), playerX, playerY, $gamePlayer.collider() ) ) { | |
this.start(); | |
} | |
} | |
}; | |
} )(); | |
} )(); | |
/** | |
* Game_Interpreter | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
var Game_Interpreter_command101 = Game_Interpreter.prototype.command101; | |
Game_Interpreter.prototype.command101 = function(params) { | |
Game_Interpreter_command101.call( this, params ); | |
$gamePlayer._touchTarget = null; | |
}; | |
} )(); | |
} )(); | |
/** | |
* Game_Map | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
var Game_Map_setup = Game_Map.prototype.setup; | |
Game_Map.prototype.setup = function( mapId ) { | |
Game_Map_setup.call( this, mapId ); | |
if ( !$gameSystem._eventColliders[mapId] ) { | |
$gameSystem._eventColliders[mapId] = []; | |
} | |
}; | |
Game_Map.prototype.tileId = function( x, y, z ) { | |
x = x | 0; | |
y = y | 0; | |
var width = $dataMap.width; | |
var height = $dataMap.height; | |
return $dataMap.data[( z * height + y ) * width + x] || 0; | |
}; | |
Game_Map.prototype.canvasToMapX = function( x ) { | |
var tileWidth = this.tileWidth(); | |
var originX = this._displayX * tileWidth; | |
var mapX = ( originX + x ) / tileWidth; | |
return this.roundX( mapX ); | |
}; | |
Game_Map.prototype.canvasToMapY = function( y ) { | |
var tileHeight = this.tileHeight(); | |
var originY = this._displayY * tileHeight; | |
var mapY = ( originY + y ) / tileHeight; | |
return this.roundY( mapY ); | |
}; | |
} )(); | |
/** | |
* Extensions | |
*/ | |
( function() { | |
Game_Map.prototype.directionX = function( ax, bx ) { | |
if ( this.isLoopHorizontal() ) { | |
var dxA = bx - ax; | |
var dxB = ( bx - this.width() ) - ax; | |
var dxC = ( bx + this.width() ) - ax; | |
dx = Math.abs( dxA ) < Math.abs( dxB ) ? dxA : dxB; | |
return Math.abs( dx ) < Math.abs( dxC ) ? dx : dxC; | |
} else { | |
return bx - ax; | |
} | |
}; | |
Game_Map.prototype.directionY = function( ay, by ) { | |
if ( this.isLoopVertical() ) { | |
var dyA = by - ay; | |
var dyB = ( by - this.height() ) - ay; | |
var dyC = ( by + this.height() ) - ay; | |
dy = Math.abs( dyA ) < Math.abs( dyB ) ? dyA : dyB; | |
return Math.abs( dy ) < Math.abs( dyC ) ? dy : dyC; | |
} else { | |
return by - ay; | |
} | |
}; | |
Game_Map.prototype.collisionMesh = function( collisionType ) { | |
collisionType = collisionType || CollisionMesh.WALK; | |
return CollisionMesh.getMesh( this.mapId(), collisionType ); | |
} | |
Game_Map.prototype.getCharactersUnderPoint = function( x, y ) { | |
return this.characters().filter( function( entry ) { | |
if ( !entry ) { | |
return false; | |
} | |
var aabbox = entry.collider().aabbox; | |
if ( x < entry._x + aabbox.left ) { | |
return false; | |
} else if ( x > entry._x + aabbox.right ) { | |
return false; | |
} else if ( y < entry._y + aabbox.top ) { | |
return false; | |
} else if ( y > entry._y + aabbox.bottom ) { | |
return false; | |
} | |
return true; | |
} ); | |
}; | |
Game_Map.prototype.getCharactersUnder = function( character, x, y ) { | |
var vx = x - character.x; | |
var vy = y - character.y; | |
var collider = character.collider(); | |
var bboxTests = this.getAABBoxTests( character, vx, vy ); | |
// Gather any solid characters within the movement bounding box | |
var loopMap = {}; | |
var characters = this.characters().filter( function( entry ) { | |
if ( !entry ) { | |
return false; | |
} | |
for ( var ii = 0; ii < bboxTests.length; ii++ ) { | |
if ( Collider.aabboxCheck( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, entry._x, entry._y, entry.collider().aabbox ) ) { | |
loopMap[entry] = bboxTests[ii].type; | |
return true; | |
} | |
} | |
return false; | |
} ); | |
characters = characters.filter( function( character ) { | |
var entryX = character._x; | |
var entryY = character._y; | |
if ( loopMap[character] == 1 ) { entryX += $gameMap.width(); } | |
else if ( loopMap[character] == 2 ) { entryX -= $gameMap.width(); } | |
else if ( loopMap[character] == 3 ) { entryY += $gameMap.height(); } | |
else if ( loopMap[character] == 4 ) { entryY -= $gameMap.height(); } | |
else if ( loopMap[character] == 5 ) { entryX += $gameMap.width(); entryY += $gameMap.height(); } | |
else if ( loopMap[character] == 6 ) { entryX -= $gameMap.width(); entryY += $gameMap.height(); } | |
else if ( loopMap[character] == 7 ) { entryX += $gameMap.width(); entryY -= $gameMap.height(); } | |
else if ( loopMap[character] == 8 ) { entryX -= $gameMap.width(); entryY -= $gameMap.height(); } | |
return Collider.intersect( x, y, collider, entryX, entryY, character.collider() ); | |
} ); | |
return characters; | |
}; | |
Game_Map.prototype.getTilesUnder = function( character, vx, vy ) { | |
vx = vx || 0; | |
vy = vy || 0; | |
var collider = character.collider(); | |
var bboxTests = this.getAABBoxTests( character, vx, vy ); | |
var tiles = []; | |
// Test collision with map | |
var left = Math.floor( character._x + vx + collider.aabbox.left ); | |
var top = Math.floor( character._y + vy + collider.aabbox.top ); | |
var right = Math.ceil( character._x + vx + collider.aabbox.right - Number.EPSILON ); | |
var bottom = Math.ceil( character._y + vy + collider.aabbox.bottom - Number.EPSILON ); | |
var tileCollider = Collider.sharedTile(); | |
for ( var yy = top; yy < bottom; yy++ ) { | |
for ( var xx = left; xx < right; xx++ ) { | |
if ( Collider.intersect( character._x + vx, character._y + vy, collider, xx, yy, tileCollider ) ) { | |
tiles.push( [xx, yy] ); | |
} | |
} | |
} | |
return tiles; | |
}; | |
Game_Map.prototype.touchesCharacters = function( character, x, y ) { | |
var vx = x - character.x; | |
var vy = y - character.y; | |
var collider = character.collider(); | |
var bboxTests = this.getAABBoxTests( character, vx, vy ); | |
// Gather any solid characters within the movement bounding box | |
var loopMap = {}; | |
var characters = $gameMap.characters().filter( function( entry ) { | |
if ( character.collidableWith( entry ) ) { | |
for ( var ii = 0; ii < bboxTests.length; ii++ ) { | |
if ( Collider.aabboxCheck( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, entry._x, entry._y, entry.collider().aabbox ) ) { | |
loopMap[entry] = bboxTests[ii].type; | |
return true; | |
} | |
} | |
} | |
return false; | |
} ); | |
// Test collision with characters | |
for ( var ii = 0; ii < characters.length; ii++ ) { | |
var entryX = characters[ii]._x; | |
var entryY = characters[ii]._y; | |
if ( loopMap[characters[ii]] == 1 ) { entryX += this.width(); } | |
else if ( loopMap[characters[ii]] == 2 ) { entryX -= this.width(); } | |
else if ( loopMap[characters[ii]] == 3 ) { entryY += this.height(); } | |
else if ( loopMap[characters[ii]] == 4 ) { entryY -= this.height(); } | |
else if ( loopMap[characters[ii]] == 5 ) { entryX += this.width(); entryY += this.height(); } | |
else if ( loopMap[characters[ii]] == 6 ) { entryX -= this.width(); entryY += this.height(); } | |
else if ( loopMap[characters[ii]] == 7 ) { entryX += this.width(); entryY -= this.height(); } | |
else if ( loopMap[characters[ii]] == 8 ) { entryX -= this.width(); entryY -= this.height(); } | |
if ( Collider.intersect( x, y, collider, entryX, entryY, characters[ii].collider() ) ) { | |
return true; | |
} | |
} | |
return false; | |
}; | |
Game_Map.prototype.canMoveOn = function( character, x, y, collisionMesh ) { | |
var collider = character.collider(); | |
var xd = x - character._x; | |
var yd = y - character._y; | |
var bboxTests = this.getAABBoxTests( character, xd, yd ); | |
// Gather any solid characters within the movement bounding box | |
var loopMap = {}; | |
var characters = $gameMap.characters().filter( function( entry ) { | |
if ( character.collidableWith( entry ) ) { | |
for ( var ii = 0; ii < bboxTests.length; ii++ ) { | |
if ( Collider.aabboxCheck( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, entry._x, entry._y, entry.collider().aabbox ) ) { | |
loopMap[entry] = bboxTests[ii].type; | |
return true; | |
} | |
} | |
} | |
return false; | |
} ); | |
// Test collision with characters | |
for ( var ii = 0; ii < characters.length; ii++ ) { | |
var entry = characters[ii]; | |
var entryX = entry._x; | |
var entryY = entry._y; | |
if ( loopMap[entry] == 1 ) { entryX += this.width(); } | |
else if ( loopMap[entry] == 2 ) { entryX -= this.width(); } | |
else if ( loopMap[entry] == 3 ) { entryY += this.height(); } | |
else if ( loopMap[entry] == 4 ) { entryY -= this.height(); } | |
else if ( loopMap[entry] == 5 ) { entryX += this.width(); entryY += this.height(); } | |
else if ( loopMap[entry] == 6 ) { entryX -= this.width(); entryY += this.height(); } | |
else if ( loopMap[entry] == 7 ) { entryX += this.width(); entryY -= this.height(); } | |
else if ( loopMap[entry] == 8 ) { entryX -= this.width(); entryY -= this.height(); } | |
if ( Collider.intersect( character._x, character._y, collider, entryX, entryY, entry.collider() ) ) { | |
return false; | |
} | |
} | |
// Test collision with map | |
for ( var ii = 0; ii < bboxTests.length; ii++ ) { | |
var offsetX = 0; | |
var offsetY = 0; | |
if ( bboxTests[ii].type == 1 ) { offsetX += this.width(); } | |
else if ( bboxTests[ii].type == 2 ) { offsetX -= this.width(); } | |
else if ( bboxTests[ii].type == 3 ) { offsetY += this.height(); } | |
else if ( bboxTests[ii].type == 4 ) { offsetY -= this.height(); } | |
else if ( bboxTests[ii].type == 5 ) { offsetX += this.width(); offsetY += this.height(); } | |
else if ( bboxTests[ii].type == 6 ) { offsetX -= this.width(); offsetY += this.height(); } | |
else if ( bboxTests[ii].type == 7 ) { offsetX += this.width(); offsetY -= this.height(); } | |
else if ( bboxTests[ii].type == 8 ) { offsetX -= this.width(); offsetY -= this.height(); } | |
var mapColliders = Collider.polygonsWithinColliderList( bboxTests[ii].x, bboxTests[ii].y, bboxTests[ii].aabbox, 0, 0, collisionMesh ); | |
if ( mapColliders.length > 0 ) { | |
for ( var jj = 0; jj < mapColliders.length; jj++ ) { | |
if ( Collider.intersect( x, y, collider, offsetX, offsetY, mapColliders[jj] ) ) { | |
return false; | |
} | |
} | |
} | |
} | |
return true; | |
}; | |
Game_Map.prototype.isAABBoxValid = function( x, y, aabbox ) { | |
return aabbox.left + x >= 0 && aabbox.right + x <= this.width() && aabbox.top + y >= 0 && aabbox.bottom + y <= this.height(); | |
}; | |
Game_Map.prototype.canWalk = function( character, x, y ) { | |
// Passability test | |
if ( !this.checkPassage( x, y, 0x0f ) ) { | |
return false; | |
} | |
return this.canMoveOn( character, x, y, CollisionMesh.getMesh( this.mapId(), CollisionMesh.WALK ) ); | |
}; | |
Game_Map.prototype.getAABBoxTests = function( character, vx, vy ) { | |
var aabbox = character.collider().aabbox; | |
if ( vx || vy ) { | |
// Extend aabbox for vectors | |
aabbox = { | |
left: aabbox.left + ( vx < 0 ? vx : 0 ), | |
top: aabbox.top + ( vy < 0 ? vy : 0 ), | |
right: aabbox.right + ( vx > 0 ? vx : 0 ), | |
bottom: aabbox.bottom + ( vy > 0 ? vy : 0 ) | |
}; | |
} | |
// Construct aabbox tests for map edges | |
var bboxTests = [ { x: character._x, y: character._y, aabbox: aabbox, type: 0 } ]; | |
if ( this.isLoopHorizontal() ) { | |
bboxTests.push( { x: character._x - this.width(), y: character._y, aabbox: aabbox, type: 1 } ); | |
bboxTests.push( { x: character._x + this.width(), y: character._y, aabbox: aabbox, type: 2 } ); | |
} | |
if ( this.isLoopVertical() ) { | |
bboxTests.push( { x: character._x, y: character._y - this.height(), aabbox: aabbox, type: 3 } ); | |
bboxTests.push( { x: character._x, y: character._y + this.height(), aabbox: aabbox, type: 4 } ); | |
} | |
if ( this.isLoopHorizontal() && this.isLoopVertical() ) { | |
bboxTests.push( { x: character._x - this.width(), y: character._y - this.height(), aabbox: aabbox, type: 5 } ); | |
bboxTests.push( { x: character._x + this.width(), y: character._y - this.height(), aabbox: aabbox, type: 6 } ); | |
bboxTests.push( { x: character._x - this.width(), y: character._y + this.height(), aabbox: aabbox, type: 7 } ); | |
bboxTests.push( { x: character._x + this.width(), y: character._y + this.height(), aabbox: aabbox, type: 8 } ); | |
} | |
return bboxTests; | |
}; | |
Game_Map.prototype.characters = function() { | |
return this._events.concat( $gamePlayer, this._vehicles, $gamePlayer._followers._data ); | |
}; | |
} )(); | |
} )(); | |
/** | |
* Sprite_Destination | |
*/ | |
( function() { | |
/** | |
* Overrides | |
*/ | |
( function() { | |
Sprite_Destination.prototype.createBitmap = function() { | |
var tileWidth = $gameMap.tileWidth(); | |
var tileHeight = $gameMap.tileHeight(); | |
this.bitmap = new Bitmap( tileWidth, tileHeight ); | |
this.bitmap.drawCircle( tileWidth / 2, tileHeight / 2, ( tileWidth < tileHeight ? tileWidth : tileHeight ) / 2, 'white' ); | |
this.anchor.x = 0.5; | |
this.anchor.y = 0.5; | |
this.blendMode = PIXI.BLEND_MODES.ADD; | |
}; | |
Sprite_Destination.prototype.update = function() { | |
Sprite.prototype.update.call( this ); | |
if ( $gamePlayer._touchTarget ){ | |
this.updatePosition(); | |
this.updateAnimation(); | |
this.visible = true; | |
} else { | |
this._frameCount = 0; | |
this.visible = false; | |
} | |
}; | |
Sprite_Destination.prototype.updatePosition = function() { | |
var tileWidth = $gameMap.tileWidth(); | |
var tileHeight = $gameMap.tileHeight(); | |
var x = $gamePlayer._touchTarget.x; | |
var y = $gamePlayer._touchTarget.y; | |
this.x = ( $gameMap.adjustX( x ) + 0.5 ) * tileWidth; | |
this.y = ( $gameMap.adjustY( y ) + 0.5 ) * tileHeight; | |
}; | |
} )(); | |
} )(); | |
/** | |
* CollisionMesh | |
*/ | |
function CollisionMesh() { | |
throw new Error( 'This is a static class' ); | |
} | |
( function() { | |
CollisionMesh.WALK = 0; | |
CollisionMesh.BOAT = 1; | |
CollisionMesh.SHIP = 2; | |
CollisionMesh.AIRSHIP = 3; | |
CollisionMesh.meshInMemory = { mapId: null, mesh: [] }; | |
CollisionMesh.getMesh = function( mapId, type ) { | |
type = type || CollisionMesh.WALK; | |
if ( CollisionMesh.meshInMemory.mapId === mapId ) { | |
return CollisionMesh.meshInMemory.mesh[type]; | |
} | |
var cacheName = 'cache_mesh%1'.format( mapId.padZero( 3 ) ); | |
if ( ( PLAY_TEST.COLLISION_MESH_CACHING && $gameTemp.isPlaytest() ) && StorageManager.exists( cacheName ) ) { | |
CollisionMesh.meshInMemory.mapId = mapId; | |
CollisionMesh.meshInMemory.mesh = JsonEx.parse( StorageManager.load( cacheName ) ); | |
} else { | |
var gameMap; | |
if ( $gameMap.mapId() === mapId ) { | |
gameMap = $gameMap; | |
} else { | |
gameMap = new Game_Map(); | |
gameMap.setup( mapId ); | |
} | |
CollisionMesh.meshInMemory.mapId = mapId; | |
CollisionMesh.meshInMemory.mesh[CollisionMesh.WALK] = CollisionMesh.makeCollisionMesh( gameMap, gameMap.isPassable ); | |
if ( !gameMap.boat().isTransparent() ) { | |
CollisionMesh.meshInMemory.mesh[CollisionMesh.BOAT] = CollisionMesh.makeCollisionMesh( gameMap, gameMap.isBoatPassable ); | |
} | |
if ( !gameMap.ship().isTransparent() ) { | |
CollisionMesh.meshInMemory.mesh[CollisionMesh.SHIP] = CollisionMesh.makeCollisionMesh( gameMap, gameMap.isShipPassable ); | |
} | |
if ( !gameMap.airship().isTransparent() ) { | |
CollisionMesh.meshInMemory.mesh[CollisionMesh.AIRSHIP] = CollisionMesh.makeCollisionMesh( gameMap ); | |
} | |
StorageManager.saveObject( cacheName, JSON.prune( CollisionMesh.meshInMemory.mesh ) ); | |
} | |
return CollisionMesh.meshInMemory.mesh[type]; | |
}; | |
CollisionMesh.addTileDCollisionObject = function( x, y, object, scale, tileWidth, tileHeight, colliders ) { | |
x += object.x / tileWidth; | |
y += object.y / tileHeight; | |
if ( object.polygon ) { | |
// Polygon | |
var polygon = []; | |
for ( var ii = 0; ii < object.polygon.length; ii++ ) { | |
polygon[ii] = [ | |
x + ( object.polygon[ii].x / tileWidth ), | |
y + ( object.polygon[ii].y / tileHeight ) | |
]; | |
} | |
colliders.push( Collider.createPolygon( polygon ) ); | |
} else if ( object.polyline ) { | |
// Polyline | |
var polylines; | |
if ( object.polyline.length == 2 ) { | |
polylines = Collider.createPolygon( [ | |
[x + ( object.polyline[0].x / tileWidth ), y + ( object.polyline[0].y / tileWidth )], | |
[x + ( object.polyline[1].x / tileHeight ), y + ( object.polyline[1].y / tileHeight )] | |
] ); | |
} else { | |
polylines = Collider.createList(); | |
for ( var ii = 0; ii < ( object.polyline.length - 1 ); ii++ ) { | |
Collider.addToList( polylines, Collider.createPolygon( [ | |
[x + ( object.polyline[ii].x / tileWidth ), y + ( object.polyline[ii].y / tileWidth )], | |
[x + ( object.polyline[ii + 1].x / tileHeight ), y + ( object.polyline[ii + 1].y / tileHeight )] | |
] ) ); | |
} | |
} | |
colliders.push( polylines ); | |
} else if ( object.ellipse ) { | |
// Ellipse | |
if ( object.width == object.height ) { | |
// Circle | |
var rad = ( object.width / tileWidth ) / 2; | |
colliders.push( Collider.createCircle( x + rad, y + rad, rad ) ); | |
} else { | |
// Regular polygon | |
var rx = ( object.width / tileWidth ) / 2; | |
var ry = ( object.height / tileHeight ) / 2; | |
var points = ( object.properties && object.properties.points ) ? object.properties.points : 8; | |
colliders.push( Collider.createRegularPolygon( x + rx, y + ry, rx, ry, points ) ); | |
} | |
} else { | |
// Rect | |
var w = object.width / tileWidth; | |
var h = object.height / tileHeight; | |
colliders.push( Collider.createRect( x, y, w, h ) ); | |
} | |
}; | |
CollisionMesh.makeCollisionMesh = function( gameMap, passFunc ) { | |
// Make collision mask | |
var collisionGrid = []; | |
if ( !passFunc ) { | |
passFunc = function( x, y, d ) { return true; }; | |
} | |
for ( var xx = 0; xx < gameMap.width(); xx++ ) { | |
collisionGrid[xx] = []; | |
for ( var yy = 0; yy < gameMap.height(); yy++ ) { | |
collisionGrid[xx][yy] = 0; | |
if ( !passFunc.call( gameMap, xx, yy, Direction.UP ) ) { | |
collisionGrid[xx][yy] |= ( 0x1 << 0 ); | |
} | |
if ( !passFunc.call( gameMap, xx, yy, Direction.LEFT ) ) { | |
collisionGrid[xx][yy] |= ( 0x1 << 1 ); | |
} | |
if ( !passFunc.call( gameMap, xx, yy, Direction.DOWN ) ) { | |
collisionGrid[xx][yy] |= ( 0x1 << 2 ); | |
} | |
if ( !passFunc.call( gameMap, xx, yy, Direction.RIGHT ) ) { | |
collisionGrid[xx][yy] |= ( 0x1 << 3 ); | |
} | |
} | |
} | |
var colliders = []; | |
var d = 2; | |
// Non-looping sides | |
if ( !gameMap.isLoopHorizontal() ) { | |
var q = gameMap.isLoopVertical() ? 0 : d; | |
colliders.push( Collider.createPolygon( | |
[ [ 0, 0 ], [ 0, gameMap.height() ], [ -d, gameMap.height() + q ] , [ -d, -q ] ] | |
) ); | |
colliders.push( Collider.createPolygon( | |
[ [ gameMap.width(), gameMap.height() ], [ gameMap.width(), 0 ], [ gameMap.width() + d, -q ], [ gameMap.width() + d, gameMap.height() + q ] ] | |
) ); | |
} | |
if ( !gameMap.isLoopVertical() ) { | |
var q = gameMap.isLoopHorizontal() ? 0 : d; | |
colliders.push( Collider.createPolygon( | |
[ [ gameMap.width(), 0 ], [ 0, 0 ], [ -q, -d ], [ gameMap.width() + q, -d ] ] | |
) ); | |
colliders.push( Collider.createPolygon( | |
[ [ 0, gameMap.height() ], [ gameMap.width(), gameMap.height() ], [ gameMap.width() + q, gameMap.height() + d ], [ -q, gameMap.height() + d ] ] | |
) ); | |
} | |
// Build tiles (Fixes some cases for humpy corner collision) | |
for ( var yy = 0; yy < gameMap.height(); yy++ ) { | |
var top = gameMap.roundY( yy - 1 ); | |
var bottom = gameMap.roundY( yy + 1 ); | |
for ( var xx = 0; xx < gameMap.width(); xx++ ) { | |
if ( collisionGrid[xx][yy] !== 0xf ) { | |
continue; | |
} | |
var left = gameMap.roundX( xx - 1 ); | |
var right = gameMap.roundX( xx + 1 ); | |
var open = 0; | |
if ( left < 0 || collisionGrid[left][yy] == 0 ) { | |
open++; | |
} | |
if ( top < 0 || collisionGrid[xx][top] == 0 ) { | |
open++; | |
} | |
if ( right >= gameMap.width() || collisionGrid[right][yy] == 0 ) { | |
open++; | |
} | |
if ( bottom >= gameMap.height() || collisionGrid[xx][bottom] == 0 ) { | |
open++; | |
} | |
if ( open === 4 ) { | |
collisionGrid[xx][yy] = 0; | |
colliders.push( Collider.createPolygon( [ | |
[ xx, yy ], | |
[ xx + 1, yy ], | |
[ xx + 1, yy + 1 ], | |
[ xx, yy + 1 ], | |
] ) ); | |
} | |
} | |
} | |
// Build horizontal lines | |
var horizontalLine = null; | |
var hColliders = []; | |
for ( var yy = 0; yy < gameMap.height(); yy++ ) { | |
for ( var xx = 0; xx < gameMap.width(); xx++ ) { | |
var y2 = gameMap.roundY( yy - 1 ); | |
if ( ( collisionGrid[xx][yy] & ( 0x1 << 0 ) || ( y2 >= 0 && collisionGrid[xx][y2] & ( 0x1 << 2 ) ) ) ) { | |
// Can't move up or down | |
// Is a horizontal line | |
if ( !horizontalLine ) { | |
horizontalLine = [[xx, yy]]; | |
} | |
horizontalLine[1] = [xx + 1, yy]; | |
} else if ( !!horizontalLine ) { | |
hColliders.push( Collider.createPolygon( horizontalLine ) ); | |
// hColliders.push( Collider.createPolygon( [[horizontalLine[1][0], horizontalLine[1][1]], [horizontalLine[0][0], horizontalLine[0][1]]] ) ); | |
horizontalLine = null; | |
} | |
} | |
if ( !!horizontalLine ) { | |
hColliders.push( Collider.createPolygon( horizontalLine ) ); | |
// hColliders.push( Collider.createPolygon( [[horizontalLine[1][0], horizontalLine[1][1]], [horizontalLine[0][0], horizontalLine[0][1]]] ) ); | |
horizontalLine = null; | |
} | |
} | |
// Build vertical lines | |
var verticalLine = null; | |
var vColliders = []; | |
for ( var xx = 0; xx < gameMap.width(); xx++ ) { | |
for ( var yy = 0; yy < gameMap.height(); yy++ ) { | |
var x2 = gameMap.roundX( xx - 1 ); | |
if ( ( collisionGrid[xx][yy] & ( 0x1 << 1 ) || ( x2 >= 0 && collisionGrid[x2][yy] & ( 0x1 << 3 ) ) ) ) { | |
// Can't move left or right | |
// Is a vertical line | |
if ( !verticalLine ) { | |
verticalLine = [[xx, yy]]; | |
} | |
verticalLine[1] = [xx, yy + 1]; | |
} else if ( !!verticalLine ) { | |
vColliders.push( Collider.createPolygon( verticalLine ) ); | |
// vColliders.push( Collider.createPolygon( [[verticalLine[1][0], verticalLine[1][1]], [verticalLine[0][0], verticalLine[0][1]]] ) ); | |
verticalLine = null; | |
} | |
} | |
if ( !!verticalLine ) { | |
vColliders.push( Collider.createPolygon( verticalLine ) ); | |
// vColliders.push( Collider.createPolygon( [[verticalLine[1][0], verticalLine[1][1]], [verticalLine[0][0], verticalLine[0][1]]] ) ); | |
verticalLine = null; | |
} | |
} | |
// TileD colliders | |
if ( gameMap.tiledData ) { | |
var tileWidth = gameMap.tileWidth(); | |
var tileHeight = gameMap.tileHeight(); | |
var scale = ( gameMap.isHalfTile && gameMap.isHalfTile() ) ? 2 : 1; | |
var tilesetColliders = []; | |
// Build tile colliders | |
var tilesets = gameMap.tiledData.tilesets; | |
for ( var ii = 0; ii < tilesets.length; ii++ ) { | |
tilesetColliders[ii] = {}; | |
var tiles = tilesets[ii].tiles; | |
for ( var key in tiles ) { | |
if ( tiles[key].objectgroup ) { | |
tilesetColliders[ii][key] = tiles[key].objectgroup.objects; | |
} | |
} | |
} | |
// Place tile colliders | |
for ( var ii = 0; ii < gameMap.tiledData.layers.length; ii++ ) { | |
var layer = gameMap.tiledData.layers[ii]; | |
for ( var yy = 0; yy < layer.height; yy++ ) { | |
var row = yy * layer.width; | |
for ( var xx = 0; xx < layer.width; xx++ ) { | |
var tileId = layer.data[row + xx]; | |
if ( tileId === 0 ) { | |
continue; | |
} | |
tileId++; | |
// Find tileset belonging to tileId | |
var tilesetId = -1; | |
var firstId = 0; | |
for ( var jj = 0; jj < gameMap.tiledData.tilesets.length; jj++ ) { | |
firstId = gameMap.tiledData.tilesets[jj].firstgid; | |
var lastId = firstId + gameMap.tiledData.tilesets[jj].tilecount; | |
if ( tileId >= firstId && tileId <= lastId ) { | |
tilesetId = jj; | |
break; | |
} | |
} | |
if ( tilesetId < 0 ) { | |
continue; | |
} | |
// Get objectGroup for this tileId | |
var tileSet = tilesetColliders[tilesetId]; | |
var objectGroup = tileSet['' + ( tileId - firstId - 1 )]; | |
if ( objectGroup ) { | |
for ( var jj = 0; jj < objectGroup.length; jj++ ) { | |
var object = objectGroup[jj]; | |
var x = xx * scale; | |
var y = yy * scale; | |
CollisionMesh.addTileDCollisionObject( x, y, object, scale, tileWidth, tileHeight, colliders ); | |
} | |
} | |
} | |
} | |
} | |
// Find collision mesh layers | |
for ( var ii = 0; ii < gameMap.tiledData.layers.length; ii++ ) { | |
var layer = gameMap.tiledData.layers[ii]; | |
if ( layer.type == "objectgroup" && layer.properties && layer.properties.collision == "mesh" ) { | |
for ( var jj = 0; jj < layer.objects.length; jj++ ) { | |
CollisionMesh.addTileDCollisionObject( 0, 0, layer.objects[jj], scale, tileWidth, tileHeight, colliders ); | |
} | |
} | |
} | |
} | |
// We sort the horizontal and vertical lines separately as we check | |
// map collision in two stages: horizontal then vertical | |
var collisionMesh = Collider.createList(); | |
if ( colliders.length > 0 ) { | |
Collider.addToList( collisionMesh, Collider.treeFromArray( colliders ) ); | |
} | |
if ( hColliders.length > 0 ) { | |
Collider.addToList( collisionMesh, Collider.treeFromArray( hColliders ) ); | |
} | |
if ( vColliders.length > 0 ) { | |
Collider.addToList( collisionMesh, Collider.treeFromArray( vColliders ) ); | |
} | |
return collisionMesh; | |
}; | |
} )(); | |
/** | |
* Collider | |
* Utility for managing colliders | |
*/ | |
function Collider() { | |
throw new Error( 'This is a static class' ); | |
} | |
( function() { | |
Collider.CIRCLE = 0; | |
Collider.POLYGON = 1; | |
Collider.LIST = 2; | |
Collider.PRECISION = Math.pow( 2, 7 ); | |
Collider.I_PRECISION = 1 / Collider.PRECISION; | |
Collider.PRESETS = []; | |
Collider.createList = function() { | |
return { type: Collider.LIST, colliders: [], aabbox: { left: Number.POSITIVE_INFINITY, top: Number.POSITIVE_INFINITY, right: Number.NEGATIVE_INFINITY, bottom: Number.NEGATIVE_INFINITY } }; | |
}; | |
Collider.addToList = function( list, collider ) { | |
list.colliders.push( collider ); | |
list.aabbox.left = collider.aabbox.left < list.aabbox.left ? collider.aabbox.left : list.aabbox.left; | |
list.aabbox.top = collider.aabbox.top < list.aabbox.top ? collider.aabbox.top : list.aabbox.top; | |
list.aabbox.right = collider.aabbox.right > list.aabbox.right ? collider.aabbox.right : list.aabbox.right; | |
list.aabbox.bottom = collider.aabbox.bottom > list.aabbox.bottom ? collider.aabbox.bottom : list.aabbox.bottom; | |
}; | |
Collider.getPreset = function( id ) { | |
if ( Collider.PRESETS.length === 0 ) { | |
// Index starts at 1 (first item is null collider) | |
Collider.PRESETS[0] = Collider.null(); | |
for ( var ii = 0; ii < PRESETS.length; ii++ ) { | |
var xmlDoc = DOM_PARSER.parseFromString( '<collider>' + JSON.parse( PRESETS[ii] ) + '</collider>', 'text/xml' ); | |
Collider.PRESETS[ii + 1] = Collider.createFromXML( xmlDoc ); | |
var childNodes = xmlDoc.childNodes[0].childNodes; | |
for ( var jj = 0; jj < childNodes.length; jj++ ) { | |
if ( childNodes[jj].nodeName === 'name' ) { | |
Collider.PRESETS[childNodes[jj].innerHTML.trim()] = Collider.PRESETS[ii + 1]; | |
break; | |
} | |
} | |
} | |
} | |
return Collider.PRESETS[id] || null; | |
}; | |
Collider.createFromXML = function( xml ) { | |
var xmlDoc = ( typeof xml === 'string' ? DOM_PARSER.parseFromString( xml, 'text/xml' ) : xml ); | |
var childNodes = xmlDoc.childNodes; | |
for ( var ii = 0; ii < xmlDoc.childNodes.length; ii++ ) { | |
if ( xmlDoc.childNodes[ii].nodeName === 'collider' ) { | |
childNodes = xmlDoc.childNodes[ii].childNodes; | |
break; | |
} | |
} | |
var filterNodes = []; | |
for ( var ii = 0; ii < childNodes.length; ii++ ) { | |
switch ( childNodes[ii].nodeName ) { | |
case 'rect': | |
case 'circle': | |
case 'line': | |
case 'polygon': | |
case 'regular': | |
filterNodes.push( childNodes[ii] ); | |
break; | |
} | |
} | |
childNodes = filterNodes; | |
if ( childNodes.length === 0 ) { | |
return Collider.null(); | |
} else if ( childNodes.length === 1 ) { | |
switch ( childNodes[0].nodeName ) { | |
case 'rect': | |
var x = Number( childNodes[0].getAttribute( 'x' ) ); | |
var y = Number( childNodes[0].getAttribute( 'y' ) ); | |
var width = Number( childNodes[0].getAttribute( 'width' ) ); | |
var height = Number( childNodes[0].getAttribute( 'height' ) ); | |
return Collider.createRect( x, y, width, height ); | |
case 'circle': | |
var cx = Number( childNodes[0].getAttribute( 'cx' ) ); | |
var cy = Number( childNodes[0].getAttribute( 'cy' ) ); | |
var r = Number( childNodes[0].getAttribute( 'r' ) ); | |
return Collider.createCircle( cx, cy, r ); | |
case 'line': | |
var x1 = Number( childNodes[0].getAttribute( 'x1' ) ); | |
var y1 = Number( childNodes[0].getAttribute( 'y1' ) ); | |
var x2 = Number( childNodes[0].getAttribute( 'x2' ) ); | |
var y2 = Number( childNodes[0].getAttribute( 'y2' ) ); | |
return Collider.createLine( x1, y1, x2, y2 ); | |
case 'polygon': | |
var points = childNodes[0].getAttribute( 'points' ).split( ' ' ); | |
for ( var jj = 0; jj < points.length; jj++ ) { | |
points[jj] = points[jj].split( ',' ); | |
for ( var kk = 0; kk < points[jj].length; kk++ ) { | |
points[jj][kk] = Number( points[jj][kk] ); | |
} | |
} | |
return Collider.createPolygon( points ); | |
case 'regular': | |
var cx = Number( childNodes[0].getAttribute( 'cx' ) ); | |
var cy = Number( childNodes[0].getAttribute( 'cy' ) ); | |
var rx = Number( childNodes[0].getAttribute( 'rx' ) ); | |
var ry = Number( childNodes[0].getAttribute( 'ry' ) ); | |
var p = Number( childNodes[0].getAttribute( 'p' ) ); | |
return Collider.createRegularPolygon( cx, cy, rx, ry, p ); | |
} | |
} else { | |
var colliderList = Collider.createList(); | |
for ( var ii = 0; ii < childNodes.length; ii++ ) { | |
switch ( childNodes[ii].nodeName ) { | |
case 'rect': | |
var x = Number( childNodes[ii].getAttribute( 'x' ) ); | |
var y = Number( childNodes[ii].getAttribute( 'y' ) ); | |
var width = Number( childNodes[ii].getAttribute( 'width' ) ); | |
var height = Number( childNodes[ii].getAttribute( 'height' ) ); | |
Collider.addToList( colliderList, Collider.createRect( x, y, width, height ) ); | |
break; | |
case 'circle': | |
var cx = Number( childNodes[ii].getAttribute( 'cx' ) ); | |
var cy = Number( childNodes[ii].getAttribute( 'cy' ) ); | |
var r = Number( childNodes[ii].getAttribute( 'r' ) ); | |
Collider.addToList( colliderList, Collider.createCircle( cx, cy, r ) ); | |
break; | |
case 'line': | |
var x1 = Number( childNodes[ii].getAttribute( 'x1' ) ); | |
var y1 = Number( childNodes[ii].getAttribute( 'y1' ) ); | |
var x2 = Number( childNodes[ii].getAttribute( 'x2' ) ); | |
var y2 = Number( childNodes[ii].getAttribute( 'y2' ) ); | |
Collider.addToList( colliderList, Collider.createLine( x1, y1, x2, y2 ) ); | |
break; | |
case 'polygon': | |
var points = childNodes[ii].getAttribute( 'points' ).split( ' ' ); | |
for ( var jj = 0; jj < points.length; jj++ ) { | |
points[jj] = points[jj].split( ',' ); | |
for ( var kk = 0; kk < points[jj].length; kk++ ) { | |
points[jj][kk] = Number( points[jj][kk] ); | |
} | |
} | |
Collider.addToList( colliderList, Collider.createPolygon( points ) ); | |
break; | |
case 'regular': | |
var cx = Number( childNodes[ii].getAttribute( 'cx' ) ); | |
var cy = Number( childNodes[ii].getAttribute( 'cy' ) ); | |
var rx = Number( childNodes[ii].getAttribute( 'rx' ) ); | |
var ry = Number( childNodes[ii].getAttribute( 'ry' ) ); | |
var p = Number( childNodes[ii].getAttribute( 'p' ) ); | |
Collider.addToList( colliderList, Collider.createRegularPolygon( cx, cy, rx, ry, p ) ); | |
break; | |
} | |
} | |
return colliderList; | |
} | |
}; | |
Collider.createRect = function( x, y, width, height ) { | |
return Collider.createPolygon( [ | |
[ x, y ], | |
[ x + width, y ], | |
[ x + width, y + height ], | |
[ x, y + height ] | |
] ); | |
}; | |
Collider.createLine = function( x1, y1, x2, y2 ) { | |
return Collider.createPolygon( [ | |
[ x1, y1 ], | |
[ x2, y2 ], | |
] ); | |
}; | |
Collider.createCircle = function( x, y, radius ) { | |
return { type: Collider.CIRCLE, x: x, y: y, radius: radius, aabbox: { left: x - radius, top: y - radius, right: x + radius, bottom: y + radius } }; | |
}; | |
Collider.createPolygon = function( vertices ) { | |
var aabbox = { | |
left: Number.POSITIVE_INFINITY, | |
top: Number.POSITIVE_INFINITY, | |
right: Number.NEGATIVE_INFINITY, | |
bottom: Number.NEGATIVE_INFINITY, | |
}; | |
vertices.forEach( function( vertex ) { | |
if ( vertex[0] < aabbox.left ) { aabbox.left = vertex[0]; } | |
if ( vertex[1] < aabbox.top ) { aabbox.top = vertex[1]; } | |
if ( vertex[0] > aabbox.right ) { aabbox.right = vertex[0]; } | |
if ( vertex[1] > aabbox.bottom ) { aabbox.bottom = vertex[1]; } | |
} ); | |
return { type: Collider.POLYGON, vertices: vertices, aabbox: aabbox }; | |
}; | |
Collider.createRegularPolygon = function( x, y, sx, sy, points ) { | |
if ( !points || points < 3 ) { | |
return Collider.createCircle( x, y, Math.sqrt( sx * sx + sy * sy ) ); | |
} | |
var vertices = []; | |
var divisor = points / ( Math.PI * 2 ); | |
var pi2 = Math.PI / 2; | |
for ( var ii = 0; ii < points; ii++ ) { | |
vertices.push( [ x + Math.cos( ii / divisor - pi2 ) * sx, y + Math.sin( ii / divisor - pi2 ) * sy ] ); | |
} | |
return Collider.createPolygon( vertices ); | |
}; | |
Collider.null = function() { | |
if ( !Collider._null ) { | |
Collider._null = Collider.createPolygon( [] ); | |
} | |
return Collider._null; | |
}; | |
Collider.sharedTile = function() { | |
if ( !Collider._sharedTile ) { | |
Collider._sharedTile = Collider.createPolygon( [ | |
[0, 0], | |
[1, 0], | |
[1, 1], | |
[0, 1], | |
] ); | |
} | |
return Collider._sharedTile; | |
}; | |
Collider.sharedCircle = function() { | |
if ( !Collider._sharedCircle ) { | |
Collider._sharedCircle = Collider.createCircle( 0.5, 0.5, 0.5 ); | |
} | |
return Collider._sharedCircle; | |
}; | |
Collider.sharedCharacter = function() { | |
if ( !Collider._sharedCharacter ) { | |
Collider._sharedCharacter = Collider.createCircle( 0.5, 0.7, 0.25 ); | |
} | |
return Collider._sharedCharacter; | |
}; | |
Collider.sharedAirship = function() { | |
if ( !Collider._sharedAirship ) { | |
Collider._sharedAirship = Collider.createCircle( 0.5, 0.5, 0.25 ); | |
} | |
return Collider._sharedAirship; | |
}; | |
Collider.sharedShip = function() { | |
if ( !Collider._sharedShip ) { | |
Collider._sharedShip = Collider.createCircle( 0.5, 0.5, 0.5 ); | |
} | |
return Collider._sharedShip; | |
}; | |
Collider.sharedBoat = function() { | |
if ( !Collider._sharedBoat ) { | |
Collider._sharedBoat = Collider.createCircle( 0.5, 0.5, 1 / 3 ); | |
} | |
return Collider._sharedBoat; | |
}; | |
Collider.polygonsWithinColliderList = function( ax, ay, aabbox, bx, by, bc ) { | |
var polygons = []; | |
for ( var ii = 0; ii < bc.colliders.length; ii++ ) { | |
if ( Collider.aabboxCheck( ax, ay, aabbox, bx, by, bc.colliders[ii].aabbox ) ) { | |
if ( bc.colliders[ii].type === Collider.LIST ) { | |
polygons = polygons.concat( Collider.polygonsWithinColliderList( ax, ay, aabbox, bx, by, bc.colliders[ii] ) ); | |
} else { | |
polygons.push( bc.colliders[ii] ); | |
} | |
} | |
} | |
return polygons; | |
}; | |
Collider.encaseCircleCircle = function( ax, ay, ac, bx, by, bc ) { | |
ax = ax + ac.x; | |
ay = ay + ac.y; | |
bx = bx + bc.x; | |
by = by + bc.y; | |
var dx = ax - bx; | |
var dy = ay - by; | |
var dd = dx * dx + dy * dy; | |
dd -= ( bc.radius * bc.radius ); | |
if ( dd < ac.radius * ac.radius ) { | |
return true; | |
} | |
return false; | |
}; | |
Collider.intersectCircleCircle = function( ax, ay, ac, bx, by, bc ) { | |
ax = ax + ac.x; | |
ay = ay + ac.y; | |
bx = bx + bc.x; | |
by = by + bc.y; | |
var dx = ax - bx; | |
var dy = ay - by; | |
var dd = dx * dx + dy * dy; | |
var rr = bc.radius + ac.radius; | |
if ( dd < rr * rr ) { | |
return true; | |
} | |
return false; | |
}; | |
Collider.moveCircleCircle = function( ax, ay, ac, bx, by, bc, vector ) { | |
ax = ax + ac.x; | |
ay = ay + ac.y; | |
bx = bx + bc.x; | |
by = by + bc.y; | |
var dx = ax + vector.x - bx; | |
var dy = ay + vector.y - by; | |
var dd = dx * dx + dy * dy; | |
var rr = bc.radius + ac.radius; | |
if ( dd < rr * rr ) { | |
dd = rr - Math.sqrt( dd ); | |
var dl = Math.sqrt( dx * dx + dy * dy ); | |
vector.x += ( dx / dl ) * dd; | |
vector.y += ( dy / dl ) * dd; | |
} | |
return vector; | |
}; | |
Collider.encaseCirclePolygon = function( ax, ay, ac, bx, by, bc ) { | |
var aradius = ac.radius + Collider.I_PRECISION; | |
ax = ax + ac.x; | |
ay = ay + ac.y; | |
var closestPoint = { | |
distance: Number.POSITIVE_INFINITY, | |
}; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
var dx = ( ax ) - ( bx + bc.vertices[ii][0] ); | |
var dy = ( ay ) - ( by + bc.vertices[ii][1] ); | |
var d = dx * dx + dy * dy; | |
if ( d < closestPoint.distance ) { | |
closestPoint.dx = dx; | |
closestPoint.dy = dy; | |
closestPoint.distance = d; | |
closestPoint.index = ii; | |
} | |
} | |
var planeX = closestPoint.dx; | |
var planeY = closestPoint.dy; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project circle | |
var point = planeX * ( ax ) + planeY * ( ay ); | |
var maxA = point + aradius; | |
var minA = point - aradius; | |
// Project polygon | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
var projection = planeX * ( bx + bc.vertices[ii][0] ) + planeY * ( by + bc.vertices[ii][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minB < minA || maxB > maxA ) { | |
return false; | |
} | |
var jj; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
jj = ii + 1; | |
if ( jj == bc.vertices.length ) { | |
jj = 0; | |
} | |
var planeX = bc.vertices[jj][1] - bc.vertices[ii][1]; | |
var planeY = bc.vertices[ii][0] - bc.vertices[jj][0]; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project circle | |
var point = planeX * ( ax ) + planeY * ( ay ); | |
var maxA = point + aradius; | |
var minA = point - aradius; | |
// Project polygon | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var kk = 0; kk < bc.vertices.length; kk++ ) { | |
var projection = planeX * ( bx + bc.vertices[kk][0] ) + planeY * ( by + bc.vertices[kk][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minB < minA || maxB > maxA ) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
Collider.intersectCirclePolygon = function( ax, ay, ac, bx, by, bc ) { | |
var aradius = ac.radius; | |
ax = ax + ac.x; | |
ay = ay + ac.y; | |
var closestPoint = { | |
distance: Number.POSITIVE_INFINITY, | |
}; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
var dx = ( ax ) - ( bx + bc.vertices[ii][0] ); | |
var dy = ( ay ) - ( by + bc.vertices[ii][1] ); | |
var d = dx * dx + dy * dy; | |
if ( d < closestPoint.distance ) { | |
closestPoint.dx = dx; | |
closestPoint.dy = dy; | |
closestPoint.distance = d; | |
closestPoint.index = ii; | |
} | |
} | |
var planeX = closestPoint.dx; | |
var planeY = closestPoint.dy; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project circle | |
var point = planeX * ( ax ) + planeY * ( ay ); | |
var maxA = point + aradius; | |
var minA = point - aradius; | |
// Project polygon | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
var projection = planeX * ( bx + bc.vertices[ii][0] ) + planeY * ( by + bc.vertices[ii][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minA >= maxB || maxA <= minB ) { | |
// No collision | |
return false; | |
} | |
var jj; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
jj = ii + 1; | |
if ( jj == bc.vertices.length ) { | |
jj = 0; | |
} | |
var planeX = bc.vertices[jj][1] - bc.vertices[ii][1]; | |
var planeY = bc.vertices[ii][0] - bc.vertices[jj][0]; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project circle | |
var point = planeX * ( ax ) + planeY * ( ay ); | |
var maxA = point + aradius; | |
var minA = point - aradius; | |
// Project polygon | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var kk = 0; kk < bc.vertices.length; kk++ ) { | |
var projection = planeX * ( bx + bc.vertices[kk][0] ) + planeY * ( by + bc.vertices[kk][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minA > maxB || maxA < minB ) { | |
// No collision | |
return false; | |
} | |
} | |
return true; | |
}; | |
Collider.moveCirclePolygon = function( ax, ay, ac, bx, by, bc, vector ) { | |
var aradius = ac.radius; | |
ax = ax + ac.x; | |
ay = ay + ac.y; | |
var closestPoint = { | |
distance: Number.POSITIVE_INFINITY, | |
}; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
var dx = ( ax + vector.x ) - ( bx + bc.vertices[ii][0] ); | |
var dy = ( ay + vector.y ) - ( by + bc.vertices[ii][1] ); | |
var d = dx * dx + dy * dy; | |
if ( d < closestPoint.distance ) { | |
closestPoint.dx = dx; | |
closestPoint.dy = dy; | |
closestPoint.distance = d; | |
closestPoint.index = ii; | |
} | |
} | |
var correctionDistance; | |
var correctionX; | |
var correctionY; | |
var absDistance; | |
var planeX = closestPoint.dx; | |
var planeY = closestPoint.dy; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project circle | |
var point = planeX * ( ax + vector.x ) + planeY * ( ay + vector.y ); | |
var maxA = point + aradius; | |
var minA = point - aradius; | |
// Project polygon | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
var projection = planeX * ( bx + bc.vertices[ii][0] ) + planeY * ( by + bc.vertices[ii][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minA > maxB || maxA < minB ) { | |
// No collision | |
return vector; | |
} | |
correctionDistance = maxB - minA; | |
correctionX = planeX; | |
correctionY = planeY; | |
absDistance = Math.abs( correctionDistance ); | |
var jj; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
jj = ii + 1; | |
if ( jj == bc.vertices.length ) { | |
jj = 0; | |
} | |
var planeX = bc.vertices[jj][1] - bc.vertices[ii][1]; | |
var planeY = bc.vertices[ii][0] - bc.vertices[jj][0]; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project circle | |
var point = planeX * ( ax + vector.x ) + planeY * ( ay + vector.y ); | |
var maxA = point + aradius; | |
var minA = point - aradius; | |
// Project polygon | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var kk = 0; kk < bc.vertices.length; kk++ ) { | |
var projection = planeX * ( bx + bc.vertices[kk][0] ) + planeY * ( by + bc.vertices[kk][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minA > maxB || maxA < minB ) { | |
// No collision | |
return vector; | |
} | |
var distance = maxB - minA; | |
var gap = Math.abs( distance ); | |
if ( gap < absDistance ) { | |
correctionDistance = distance; | |
correctionX = planeX; | |
correctionY = planeY; | |
absDistance = gap; | |
} | |
} | |
vector.x += correctionX * correctionDistance; | |
vector.y += correctionY * correctionDistance; | |
return vector; | |
}; | |
Collider.encasePolygonCircle = function( bx, by, bc, ax, ay, ac ) { | |
var aradius = ac.radius - Collider.I_PRECISION; | |
ax = ax + ac.x; | |
ay = ay + ac.y; | |
var closestPoint = { | |
distance: Number.POSITIVE_INFINITY, | |
}; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
var dx = ( ax ) - ( bx + bc.vertices[ii][0] ); | |
var dy = ( ay ) - ( by + bc.vertices[ii][1] ); | |
var d = dx * dx + dy * dy; | |
if ( d < closestPoint.distance ) { | |
closestPoint.dx = dx; | |
closestPoint.dy = dy; | |
closestPoint.distance = d; | |
closestPoint.index = ii; | |
} | |
} | |
var planeX = closestPoint.dx; | |
var planeY = closestPoint.dy; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project circle | |
var point = planeX * ( ax ) + planeY * ( ay ); | |
var maxA = point + aradius; | |
var minA = point - aradius; | |
// Project polygon | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
var projection = planeX * ( bx + bc.vertices[ii][0] ) + planeY * ( by + bc.vertices[ii][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minA < minB || maxA > maxB ) { | |
return false; | |
} | |
var jj; | |
for ( var ii = 0; ii < bc.vertices.length; ii++ ) { | |
jj = ii + 1; | |
if ( jj == bc.vertices.length ) { | |
jj = 0; | |
} | |
var planeX = bc.vertices[jj][1] - bc.vertices[ii][1]; | |
var planeY = bc.vertices[ii][0] - bc.vertices[jj][0]; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project circle | |
var point = planeX * ( ax ) + planeY * ( ay ); | |
var maxA = point + aradius; | |
var minA = point - aradius; | |
// Project polygon | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var kk = 0; kk < bc.vertices.length; kk++ ) { | |
var projection = planeX * ( bx + bc.vertices[kk][0] ) + planeY * ( by + bc.vertices[kk][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minA < minB || maxA > maxB ) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
Collider.intersectPolygonCircle = function( ax, ay, ac, bx, by, bc ) { | |
return Collider.intersectCirclePolygon( bx, by, bc, ax, ay, ac ); | |
}; | |
Collider.movePolygonCircle = function( ax, ay, ac, bx, by, bc, vector ) { | |
var ivector = { | |
x: -vector.x, | |
y: -vector.y, | |
}; | |
ivector = Collider.moveCirclePolygon( bx, by, bc, ax, ay, ac, ivector ); | |
vector.x = -ivector.x; | |
vector.y = -ivector.y; | |
return vector; | |
}; | |
Collider.encasePolygonPolygon = function( ax, ay, ac, bx, by, bc ) { | |
var jj; | |
var colliders = [ bc, ac ]; | |
for ( var cc = 0; cc < 2; cc++ ) { | |
for ( var ii = 0; ii < colliders[cc].vertices.length; ii++ ) { | |
jj = ii + 1; | |
if ( jj == colliders[cc].vertices.length ) { | |
jj = 0; | |
} | |
var planeX = colliders[cc].vertices[jj][1] - colliders[cc].vertices[ii][1]; | |
var planeY = colliders[cc].vertices[ii][0] - colliders[cc].vertices[jj][0]; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project polygon A | |
var minA = Number.POSITIVE_INFINITY; | |
var maxA = Number.NEGATIVE_INFINITY; | |
for ( var kk = 0; kk < ac.vertices.length; kk++ ) { | |
var projection = planeX * ( ax + ac.vertices[kk][0] ) + planeY * ( ay + ac.vertices[kk][1] ); | |
if ( projection < minA ) minA = projection; | |
if ( projection > maxA ) maxA = projection; | |
} | |
// Project polygon B | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var kk = 0; kk < bc.vertices.length; kk++ ) { | |
var projection = planeX * ( bx + bc.vertices[kk][0] ) + planeY * ( by + bc.vertices[kk][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minB < minA || maxB > maxA ) { | |
return false; | |
} | |
} | |
} | |
return true; | |
}; | |
Collider.intersectPolygonPolygon = function( ax, ay, ac, bx, by, bc ) { | |
var jj; | |
var colliders = [ bc, ac ]; | |
for ( var cc = 0; cc < 2; cc++ ) { | |
for ( var ii = 0; ii < colliders[cc].vertices.length; ii++ ) { | |
jj = ii + 1; | |
if ( jj == colliders[cc].vertices.length ) { | |
jj = 0; | |
} | |
var planeX = colliders[cc].vertices[jj][1] - colliders[cc].vertices[ii][1]; | |
var planeY = colliders[cc].vertices[ii][0] - colliders[cc].vertices[jj][0]; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project polygon A | |
var minA = Number.POSITIVE_INFINITY; | |
var maxA = Number.NEGATIVE_INFINITY; | |
for ( var kk = 0; kk < ac.vertices.length; kk++ ) { | |
var projection = planeX * ( ax + ac.vertices[kk][0] ) + planeY * ( ay + ac.vertices[kk][1] ); | |
if ( projection < minA ) minA = projection; | |
if ( projection > maxA ) maxA = projection; | |
} | |
// Project polygon B | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var kk = 0; kk < bc.vertices.length; kk++ ) { | |
var projection = planeX * ( bx + bc.vertices[kk][0] ) + planeY * ( by + bc.vertices[kk][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minA > maxB || maxA < minB ) { | |
// No collision | |
return false; | |
} | |
} | |
} | |
return true; | |
}; | |
Collider.movePolygonPolygon = function( ax, ay, ac, bx, by, bc, vector ) { | |
var correctionDistance; | |
var correctionX; | |
var correctionY; | |
var absDistance = Number.POSITIVE_INFINITY; | |
var jj; | |
var colliders = [ bc, ac ]; | |
for ( var cc = 0; cc < 2; cc++ ) { | |
for ( var ii = 0; ii < colliders[cc].vertices.length; ii++ ) { | |
jj = ii + 1; | |
if ( jj == colliders[cc].vertices.length ) { | |
jj = 0; | |
} | |
var planeX = colliders[cc].vertices[jj][1] - colliders[cc].vertices[ii][1]; | |
var planeY = colliders[cc].vertices[ii][0] - colliders[cc].vertices[jj][0]; | |
var length = Math.sqrt( planeX * planeX + planeY * planeY ); | |
planeX /= length; | |
planeY /= length; | |
// Project polygon A | |
var minA = Number.POSITIVE_INFINITY; | |
var maxA = Number.NEGATIVE_INFINITY; | |
for ( var kk = 0; kk < ac.vertices.length; kk++ ) { | |
var projection = planeX * ( ax + vector.x + ac.vertices[kk][0] ) + planeY * ( ay + vector.y + ac.vertices[kk][1] ); | |
if ( projection < minA ) minA = projection; | |
if ( projection > maxA ) maxA = projection; | |
} | |
// Project polygon B | |
var minB = Number.POSITIVE_INFINITY; | |
var maxB = Number.NEGATIVE_INFINITY; | |
for ( var kk = 0; kk < bc.vertices.length; kk++ ) { | |
var projection = planeX * ( bx + bc.vertices[kk][0] ) + planeY * ( by + bc.vertices[kk][1] ); | |
if ( projection < minB ) minB = projection; | |
if ( projection > maxB ) maxB = projection; | |
} | |
if ( minA > maxB || maxA < minB ) { | |
// No collision | |
return vector; | |
} | |
var distance = maxB - minA; | |
var gap = Math.abs( distance ); | |
if ( gap < absDistance ) { | |
correctionDistance = distance; | |
correctionX = planeX; | |
correctionY = planeY; | |
absDistance = gap; | |
} | |
} | |
} | |
vector.x += correctionX * correctionDistance; | |
vector.y += correctionY * correctionDistance; | |
return vector; | |
}; | |
/** | |
* Does collider A encase B | |
* @param {Number} ax X-position collider A | |
* @param {Number} ay Y-position collider A | |
* @param {Collider} ac Collider A | |
* @param {Number} bx X-position collider B | |
* @param {Number} by Y-position collider B | |
* @param {Collider} bc Collider B | |
* @return {Boolean} true if A encases B | |
*/ | |
Collider.encase = function( ax, ay, ac, bx, by, bc ) { | |
if ( ac.type == Collider.LIST ) { | |
for ( var ii = 0; ii < ac.colliders.length; ii++ ) { | |
if ( Collider.encase( ax, ay, ac.colliders[ii], bx, by, bc ) ) { | |
return true; | |
} | |
} | |
return false; | |
} | |
if ( bc.type == Collider.LIST ) { | |
for ( var ii = 0; ii < bc.colliders.length; ii++ ) { | |
if ( Collider.encase( ax, ay, ac, bx, by, bc.colliders[ii] ) ) { | |
return true; | |
} | |
} | |
return false; | |
} | |
if ( ac.type == Collider.CIRCLE && bc.type == Collider.CIRCLE ) { | |
// Circle circle test | |
return Collider.encaseCircleCircle( ax, ay, ac, bx, by, bc ); | |
} | |
if ( ac.type == Collider.CIRCLE && bc.type == Collider.POLYGON ) { | |
// Circle polygon test | |
return Collider.encaseCirclePolygon( ax, ay, ac, bx, by, bc ); | |
} | |
if ( ac.type == Collider.POLYGON && bc.type == Collider.CIRCLE ) { | |
// Polygon circle test | |
return Collider.encasePolygonCircle( ax, ay, ac, bx, by, bc ); | |
} | |
if ( ac.type == Collider.POLYGON && bc.type == Collider.POLYGON ) { | |
// Polygon polygon test | |
return Collider.encasePolygonPolygon( ax, ay, ac, bx, by, bc ); | |
} | |
return false; | |
}; | |
/** | |
* Do colliders A & B touch | |
* @param {Number} ax X-position collider A | |
* @param {Number} ay Y-position collider A | |
* @param {Collider} ac Collider A | |
* @param {Number} bx X-position collider B | |
* @param {Number} by Y-position collider B | |
* @param {Collider} bc Collider B | |
* @return {Boolean} true if touching, false otherwise | |
*/ | |
Collider.intersect = function( ax, ay, ac, bx, by, bc ) { | |
if ( ac.type == Collider.LIST ) { | |
for ( var ii = 0; ii < ac.colliders.length; ii++ ) { | |
if ( Collider.intersect( ax, ay, ac.colliders[ii], bx, by, bc ) ) { | |
return true; | |
} | |
} | |
return false; | |
} | |
if ( bc.type == Collider.LIST ) { | |
for ( var ii = 0; ii < bc.colliders.length; ii++ ) { | |
if ( Collider.intersect( ax, ay, ac, bx, by, bc.colliders[ii] ) ) { | |
return true; | |
} | |
} | |
return false; | |
} | |
if ( ac.type == Collider.CIRCLE && bc.type == Collider.CIRCLE ) { | |
// Circle circle test | |
return Collider.intersectCircleCircle( ax, ay, ac, bx, by, bc ); | |
} | |
if ( ac.type == Collider.CIRCLE && bc.type == Collider.POLYGON ) { | |
// Circle polygon test | |
return Collider.intersectCirclePolygon( ax, ay, ac, bx, by, bc ); | |
} | |
if ( ac.type == Collider.POLYGON && bc.type == Collider.CIRCLE ) { | |
// Polygon circle test | |
return Collider.intersectPolygonCircle( ax, ay, ac, bx, by, bc ); | |
} | |
if ( ac.type == Collider.POLYGON && bc.type == Collider.POLYGON ) { | |
// Polygon polygon test | |
return Collider.intersectPolygonPolygon( ax, ay, ac, bx, by, bc ); | |
} | |
return false; | |
}; | |
/** | |
* Move and collide A towards B | |
* @param {Number} ax X-position collider A | |
* @param {Number} ay Y-position collider A | |
* @param {Collider} ac Collider A | |
* @param {Number} bx X-position collider B | |
* @param {Number} by Y-position collider B | |
* @param {Collider} bc Collider B | |
* @param {Vector} vector Input movement vector A to B | |
* @return {Vector} New movement vector | |
*/ | |
Collider.move = function( ax, ay, ac, bx, by, bc, vector ) { | |
if ( ac.type == Collider.LIST ) { | |
for ( var ii = 0; ii < ac.colliders.length; ii++ ) { | |
vector = Collider.move( ax, ay, ac.colliders[ii], bx, by, bc, vector ); | |
if ( vector.x === 0 && vector.y === 0 ) { | |
break; | |
} | |
} | |
return vector; | |
} | |
if ( bc.type == Collider.LIST ) { | |
for ( var ii = 0; ii < bc.colliders.length; ii++ ) { | |
vector = Collider.move( ax, ay, ac, bx, by, bc.colliders[ii], vector ); | |
if ( vector.x === 0 && vector.y === 0 ) { | |
break; | |
} | |
} | |
return vector; | |
} | |
if ( ac.type == Collider.CIRCLE && bc.type == Collider.CIRCLE ) { | |
// Circle circle test | |
return Collider.moveCircleCircle( ax, ay, ac, bx, by, bc, vector ); | |
} | |
if ( ac.type == Collider.CIRCLE && bc.type == Collider.POLYGON ) { | |
// Circle polygon test | |
return Collider.moveCirclePolygon( ax, ay, ac, bx, by, bc, vector ); | |
} | |
if ( ac.type == Collider.POLYGON && bc.type == Collider.CIRCLE ) { | |
// Polygon circle test | |
return Collider.movePolygonCircle( ax, ay, ac, bx, by, bc, vector ); | |
} | |
if ( ac.type == Collider.POLYGON && bc.type == Collider.POLYGON ) { | |
// Polygon polygon test | |
return Collider.movePolygonPolygon( ax, ay, ac, bx, by, bc, vector ); | |
} | |
return vector; | |
}; | |
Collider.treeFromArray = function( colliders ) { | |
while ( colliders.length > 1 ) { | |
var shortestDist = Number.POSITIVE_INFINITY; | |
var closestNode = -1; | |
for ( var ii = 1; ii < colliders.length; ii++ ) { | |
var leftDistance = Math.abs( colliders[ii].aabbox.right - colliders[0].aabbox.left ); | |
if ( leftDistance < shortestDist ) { | |
shortestDist = leftDistance; | |
closestNode = ii; | |
continue; | |
} | |
var rightDistance = Math.abs( colliders[ii].aabbox.left - colliders[0].aabbox.right ); | |
if ( rightDistance < shortestDist ) { | |
shortestDist = rightDistance; | |
closestNode = ii; | |
continue; | |
} | |
var topDistance = Math.abs( colliders[ii].aabbox.bottom - colliders[0].aabbox.top ); | |
if ( topDistance < shortestDist ) { | |
shortestDist = topDistance; | |
closestNode = ii; | |
continue; | |
} | |
var bottomDistance = Math.abs( colliders[ii].aabbox.top - colliders[0].aabbox.bottom ); | |
if ( bottomDistance < shortestDist ) { | |
shortestDist = bottomDistance; | |
closestNode = ii; | |
continue; | |
} | |
} | |
// Create pairing | |
var pair = Collider.createList(); | |
Collider.addToList( pair, colliders[0] ); | |
Collider.addToList( pair, colliders[closestNode] ); | |
colliders.splice( closestNode, 1 ); | |
colliders[0] = pair; | |
} | |
return colliders[0]; | |
}; | |
/** | |
* Check if A and B roughly intersect with AABBoxes | |
* @param {Number} ax X-position collider A | |
* @param {Number} ay Y-position collider A | |
* @param {AABBox} ac AABBox A | |
* @param {Number} bx X-position collider B | |
* @param {Number} by Y-position collider B | |
* @param {AABBox} bc AABBox B | |
* @param {Number} vx Adjustment vector of A toB | |
* @param {Number} vy Adjustment vector of A to B | |
* @return {Boolean} True is AABBoxes intersect | |
*/ | |
Collider.aabboxCheck = function( ax, ay, ac, bx, by, bc, vx, vy ) { | |
vx = vx || 0; | |
vy = vy || 0; | |
var left = ax + ac.left + ( vx < 0 ? vx : 0 ); | |
if ( left > bx + bc.right ) { | |
return false; | |
} | |
var top = ay + ac.top + ( vy < 0 ? vy : 0 ); | |
if ( top > by + bc.bottom ) { | |
return false; | |
} | |
var right = ax + ac.right + ( vx > 0 ? vx : 0 ); | |
if ( right < bx + bc.left ) { | |
return false; | |
} | |
var bottom = ay + ac.bottom + ( vy > 0 ? vy : 0 ); | |
if ( bottom < by + bc.top ) { | |
return false; | |
} | |
return true; | |
}; | |
} )(); | |
/** | |
* Direction | |
* Utility for managing MV's directions | |
*/ | |
function Direction() { | |
throw new Error( 'This is a static class' ); | |
} | |
( function() { | |
Direction.DOWN_LEFT = 1; | |
Direction.DOWN = 2; | |
Direction.DOWN_RIGHT = 3; | |
Direction.LEFT = 4; | |
Direction.RIGHT = 6; | |
Direction.UP_LEFT = 7; | |
Direction.UP = 8; | |
Direction.UP_RIGHT = 9; | |
Direction.isUp = function( d ) { | |
return d >= 7; | |
}; | |
Direction.isRight = function( d ) { | |
return d % 3 == 0; | |
}; | |
Direction.isDown = function( d ) { | |
return d <= 3; | |
}; | |
Direction.isLeft = function( d ) { | |
return ( d + 2 ) % 3 == 0; | |
}; | |
Direction.fromVector = function( vx, vy ) { | |
if ( vx && vy ) { | |
if ( vy < 0 ) { | |
if ( vx < 0 ) { | |
return Direction.UP_LEFT; | |
} else { | |
return Direction.UP_RIGHT; | |
} | |
} else { | |
if ( vx < 0 ) { | |
return Direction.DOWN_LEFT; | |
} else { | |
return Direction.DOWN_RIGHT; | |
} | |
} | |
} else if ( vx < 0 ) { | |
return Direction.LEFT; | |
} else if ( vx > 0 ) { | |
return Direction.RIGHT; | |
} else if ( vy < 0 ) { | |
return Direction.UP; | |
} | |
return Direction.DOWN; | |
}; | |
Direction.normalize = function( vx, vy, length ) { | |
length = length || Math.sqrt( vx * vx + vy * vy ); | |
return { x: vx / length, y: vy / length, l: length }; | |
}; | |
Direction.normalizeSquare = function( vx, vy, length ) { | |
var angle = Math.atan2( vy, vx ); | |
var cos = Math.cos( angle ); | |
var sin = Math.sin( angle ); | |
if ( !length ) { | |
var absCos = Math.abs( cos ); | |
var absSin = Math.abs( sin ); | |
if ( absSin <= absCos ) { | |
length = 1 / absCos; | |
} else { | |
length = 1 / absSin; | |
} | |
} | |
return { x: vx * length, y: vy * length, l: length }; | |
}; | |
} )(); | |
/** | |
* Library extensions | |
* Additions to Javascript, if they are not available for some reason | |
*/ | |
( function() { | |
/* | |
* EPSILON | |
* Smallest floating point number greater than 0 | |
*/ | |
if ( Number.EPSILON === undefined ) { | |
Number.EPSILON = Math.pow( 2, -52 ); | |
} | |
// JSON.prune : a function to stringify any object without overflow | |
// two additional optional parameters : | |
// - the maximal depth (default : 6) | |
// - the maximal length of arrays (default : 50) | |
// You can also pass an "options" object. | |
// examples : | |
// var json = JSON.prune(window) | |
// var arr = Array.apply(0,Array(1000)); var json = JSON.prune(arr, 4, 20) | |
// var json = JSON.prune(window.location, {inheritedProperties:true}) | |
// Web site : http://dystroy.org/JSON.prune/ | |
// JSON.prune on github : https://github.com/Canop/JSON.prune | |
// This was discussed here : http://stackoverflow.com/q/13861254/263525 | |
// The code is based on Douglas Crockford's code : https://github.com/douglascrockford/JSON-js/blob/master/json2.js | |
// No effort was done to support old browsers. JSON.prune will fail on IE8. | |
(function () { | |
'use strict'; | |
var DEFAULT_MAX_DEPTH = 6; | |
var DEFAULT_ARRAY_MAX_LENGTH = 50; | |
var DEFAULT_PRUNED_VALUE = '"-pruned-"'; | |
var seen; // Same variable used for all stringifications | |
var iterator; // either forEachEnumerableOwnProperty, forEachEnumerableProperty or forEachProperty | |
// iterates on enumerable own properties (default behavior) | |
var forEachEnumerableOwnProperty = function(obj, callback) { | |
for (var k in obj) { | |
if (Object.prototype.hasOwnProperty.call(obj, k)) callback(k); | |
} | |
}; | |
// iterates on enumerable properties | |
var forEachEnumerableProperty = function(obj, callback) { | |
for (var k in obj) callback(k); | |
}; | |
// iterates on properties, even non enumerable and inherited ones | |
// This is dangerous | |
var forEachProperty = function(obj, callback, excluded) { | |
if (obj==null) return; | |
excluded = excluded || {}; | |
Object.getOwnPropertyNames(obj).forEach(function(k){ | |
if (!excluded[k]) { | |
callback(k); | |
excluded[k] = true; | |
} | |
}); | |
forEachProperty(Object.getPrototypeOf(obj), callback, excluded); | |
}; | |
Object.defineProperty(Date.prototype, "toPrunedJSON", {value:Date.prototype.toJSON}); | |
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, | |
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, | |
meta = { // table of character substitutions | |
'\b': '\\b', | |
'\t': '\\t', | |
'\n': '\\n', | |
'\f': '\\f', | |
'\r': '\\r', | |
'"' : '\\"', | |
'\\': '\\\\' | |
}; | |
function quote(string) { | |
escapable.lastIndex = 0; | |
return escapable.test(string) ? '"' + string.replace(escapable, function (a) { | |
var c = meta[a]; | |
return typeof c === 'string' | |
? c | |
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); | |
}) + '"' : '"' + string + '"'; | |
} | |
var prune = function (value, depthDecr, arrayMaxLength) { | |
var prunedString = DEFAULT_PRUNED_VALUE; | |
var replacer; | |
if (typeof depthDecr == "object") { | |
var options = depthDecr; | |
depthDecr = options.depthDecr; | |
arrayMaxLength = options.arrayMaxLength; | |
iterator = options.iterator || forEachEnumerableOwnProperty; | |
if (options.allProperties) iterator = forEachProperty; | |
else if (options.inheritedProperties) iterator = forEachEnumerableProperty | |
if ("prunedString" in options) { | |
prunedString = options.prunedString; | |
} | |
if (options.replacer) { | |
replacer = options.replacer; | |
} | |
} else { | |
iterator = forEachEnumerableOwnProperty; | |
} | |
seen = []; | |
depthDecr = depthDecr || DEFAULT_MAX_DEPTH; | |
arrayMaxLength = arrayMaxLength || DEFAULT_ARRAY_MAX_LENGTH; | |
function str(key, holder, depthDecr) { | |
var i, k, v, length, partial, value = holder[key]; | |
if (value && typeof value === 'object' && typeof value.toPrunedJSON === 'function') { | |
value = value.toPrunedJSON(key); | |
} | |
if (value && typeof value.toJSON === 'function') { | |
value = value.toJSON(); | |
} | |
switch (typeof value) { | |
case 'string': | |
return quote(value); | |
case 'number': | |
return isFinite(value) ? String(value) : 'null'; | |
case 'boolean': | |
case 'null': | |
return String(value); | |
case 'object': | |
if (!value) { | |
return 'null'; | |
} | |
if (depthDecr<=0 || seen.indexOf(value)!==-1) { | |
if (replacer) { | |
var replacement = replacer(value, prunedString, true); | |
return replacement===undefined ? undefined : ''+replacement; | |
} | |
return prunedString; | |
} | |
seen.push(value); | |
partial = []; | |
if (Object.prototype.toString.apply(value) === '[object Array]') { | |
length = Math.min(value.length, arrayMaxLength); | |
for (i = 0; i < length; i += 1) { | |
partial[i] = str(i, value, depthDecr-1) || 'null'; | |
} | |
v = '[' + partial.join(',') + ']'; | |
if (replacer && value.length>arrayMaxLength) return replacer(value, v, false); | |
return v; | |
} | |
iterator(value, function(k) { | |
try { | |
v = str(k, value, depthDecr-1); | |
if (v) partial.push(quote(k) + ':' + v); | |
} catch (e) { | |
// this try/catch due to forbidden accessors on some objects | |
} | |
}); | |
return '{' + partial.join(',') + '}'; | |
case 'function': | |
case 'undefined': | |
return replacer ? replacer(value, undefined, false) : undefined; | |
} | |
} | |
return str('', {'': value}, depthDecr); | |
}; | |
prune.log = function() { | |
console.log.apply(console, Array.prototype.map.call(arguments, function(v) { | |
return JSON.parse(JSON.prune(v)); | |
})); | |
}; | |
prune.forEachProperty = forEachProperty; // you might want to also assign it to Object.forEachProperty | |
if (typeof module !== "undefined") module.exports = prune; | |
else JSON.prune = prune; | |
}()); | |
} )(); | |
/** | |
* Plugin Commands | |
*/ | |
( function(){ | |
var logPluginCommandWarning = function(warningMsg){ | |
const currentEventId = $gameMap._interpreter._eventId; | |
const currentEvent = $gameMap.event(currentEventId); | |
if(currentEvent.name) | |
console.warn(`EV${currentEventId.toString().padStart(3, '0')}(${currentEvent.name}): ${warningMsg}`); | |
else | |
console.warn(`EV${currentEventId.toString().padStart(3, '0')}: ${warningMsg}`); | |
} | |
PluginManager.registerCommand(pluginName, "setPlayerCollider", args => { | |
const presetCollider = Collider.getPreset(args.colliderPreset); | |
if(presetCollider){ | |
$gamePlayer.setCollider(presetCollider); | |
} | |
else{ | |
logPluginCommandWarning(`Preset Collider (${args.colliderPreset}) not found!`); | |
} | |
}); | |
PluginManager.registerCommand(pluginName, "setThisCollider", args => { | |
const presetCollider = Collider.getPreset(args.colliderPreset); | |
if(presetCollider){ | |
const eventId = $gameMap._interpreter._eventId; | |
const event = $gameMap.event(eventId); | |
if(event){ | |
event.setCollider(presetCollider); | |
} | |
else{ | |
logPluginCommandWarning(`This Event (${eventId}) not found!`); | |
} | |
} | |
else{ | |
logPluginCommandWarning(`Preset Collider (${args.colliderPreset}) not found!`); | |
} | |
}); | |
PluginManager.registerCommand(pluginName, "setEventCollider", args => { | |
const presetCollider = Collider.getPreset(args.colliderPreset); | |
if(presetCollider){ | |
var eventId = args.eventId; | |
if(isNaN(eventId)) | |
{ | |
for ( var ii = 0; ii < $dataMap.events.length; ii++ ) { | |
if ( $dataMap.events[ii] && $dataMap.events[ii].name === eventId ) { | |
eventId = $dataMap.events[ii].id; | |
break; | |
} | |
} | |
} | |
if(isNaN(eventId)) | |
{ | |
logPluginCommandWarning(`Event (${eventId}) not found!`); | |
return; | |
} | |
const event = $gameMap.event(eventId); | |
if(event){ | |
event.setCollider(presetCollider); | |
} | |
else{ | |
logPluginCommandWarning(`Event (${eventId}) not found!`); | |
} | |
} | |
else{ | |
logPluginCommandWarning(`Preset Collider (${args.colliderPreset}) not found!`); | |
} | |
}); | |
PluginManager.registerCommand(pluginName, "setVehicleCollider", args => { | |
const presetCollider = Collider.getPreset(args.colliderPreset); | |
if(!presetCollider){ | |
logPluginCommandWarning(`Preset Collider (${args.colliderPreset}) not found!`); | |
return; | |
} | |
const vehicle = $gameMap.vehicle(args.vehicleId); | |
if(!vehicle){ | |
logPluginCommandWarning(`Vehicle (${args.vehicleId}) not found!`); | |
return; | |
} | |
vehicle.setCollider(presetCollider); | |
}); | |
PluginManager.registerCommand(pluginName, "setFollowerCollider", args => { | |
const presetCollider = Collider.getPreset(args.colliderPreset); | |
if(!presetCollider){ | |
logPluginCommandWarning(`Preset Collider (${args.colliderPreset}) not found!`); | |
return; | |
} | |
const follower = $gamePlayer.followers().follower(args.followerId - 1); | |
if(!follower){ | |
logPluginCommandWarning(`Follower (${args.followerId}) not found!`); | |
return; | |
} | |
follower.setCollider(presetCollider); | |
}); | |
PluginManager.registerCommand(pluginName, "setFollowersDistance", args => { | |
$gameSystem._followerDistance = args.distance; | |
}); | |
PluginManager.registerCommand(pluginName, "setFollowersFollow", args => { | |
if(args.followerId === 'all'){ | |
for(const follower of $gamePlayer.followers()._data) | |
{ | |
follower.setFrozen(args.shouldFollow); | |
} | |
} | |
else{ | |
const follower = $gamePlayer.followers().follower(args.followerId - 1); | |
if(!follower) | |
{ | |
logPluginCommandWarning(`Follower (${args.followerId}) not found!`); | |
return; | |
} | |
follower.setFrozen(args.shouldFollow === 'true'); | |
} | |
}); | |
PluginManager.registerCommand(pluginName, "move", args => { | |
var mover; | |
var skip = args.isSkippable === 'true'; | |
var wait = args.wait === 'true'; | |
const step = JSON.parse(args.moveCommand); | |
//Update mover if needed | |
if(!step.mvr){ | |
if(!mover){ | |
logPluginCommandWarning(`Mover not set!`); | |
return; | |
} | |
} | |
else if(step.mvr === 'event'){ | |
mover = JSON.stringify(step.moverEventId); | |
} | |
else if(step.mvr.startsWith('follower')) // Lower follower number to be 0 based | |
{ | |
const followerNumber = step.mvr.substring('follower'.length); | |
step.mvr = concat(step.mvr.substring(0, 'follower'.length), (followerNumber - 1)); | |
} | |
else mover = step.mvr; | |
const subMoveArgs = ['move']; | |
subMoveArgs.push(mover); | |
subMoveArgs.push(step.dir); | |
if(step.dir === 'towards' || step.dir === 'away'){ | |
var target = step.other; | |
if(step.other === 'event'){ | |
target = JSON.stringify(step.moverEventId); | |
} | |
else if(step.other.startsWith('follower')) // Lower follower number to be 0 based | |
{ | |
const followerNumber = step.other.substring('follower'.length); | |
step.other = concat(step.other.substring(0, 'follower'.length), (followerNumber - 1)); | |
} | |
subMoveArgs.push(target) | |
} | |
subMoveArgs.push(step.dist); | |
if(wait) | |
subMoveArgs.push('wait'); | |
if(skip) | |
subMoveArgs.push('skip'); | |
$gameMap._interpreter.altMovementMoveCharacter(subMoveArgs); | |
}); | |
PluginManager.registerCommand(pluginName, "setTouchMouse", args => { | |
$gameSystem._enableTouchMouse = args.value === 'true'; | |
}); | |
})(); | |
} )(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment