541 lines
15 KiB
JavaScript
541 lines
15 KiB
JavaScript
|
|
// このオブジェクトはPreAttackから使用される
|
|
var CoreAttack = defineObject(BaseObject,
|
|
{
|
|
_attackParam: null,
|
|
_battleType: 0,
|
|
_isUnitLostEventShown: false,
|
|
_attackFlow: null,
|
|
_battleObject: null,
|
|
_isBattleCut: false,
|
|
|
|
enterCoreAttackCycle: function(attackParam) {
|
|
this._prepareMemberData(attackParam);
|
|
return this._completeMemberData(attackParam);
|
|
},
|
|
|
|
moveCoreAttackCycle: function() {
|
|
if (this._battleObject.isBattleSkipAllowed() && InputControl.isStartAction()) {
|
|
this._doSkipAction();
|
|
return MoveResult.END;
|
|
}
|
|
else {
|
|
return this._battleObject.moveBattleCycle();
|
|
}
|
|
},
|
|
|
|
drawCoreAttackCycle: function() {
|
|
this._battleObject.drawBattleCycle();
|
|
},
|
|
|
|
backCoreAttackCycle: function() {
|
|
if (root.getEventCommandType() !== EventCommandType.FORCEBATTLE) {
|
|
this._battleObject.backBattleCycle();
|
|
}
|
|
},
|
|
|
|
isRealBattle: function() {
|
|
return this._battleType === BattleType.REAL;
|
|
},
|
|
|
|
getAttackFlow: function() {
|
|
return this._attackFlow;
|
|
},
|
|
|
|
getBattleObject: function() {
|
|
return this._battleObject;
|
|
},
|
|
|
|
isUnitLostEventShown: function() {
|
|
return this._isUnitLostEventShown;
|
|
},
|
|
|
|
recordUnitLostEvent: function(isShown) {
|
|
this._isUnitLostEventShown = isShown;
|
|
},
|
|
|
|
isBattleCut: function() {
|
|
return this._isBattleCut;
|
|
},
|
|
|
|
_prepareMemberData: function(attackParam) {
|
|
this._attackParam = attackParam;
|
|
this._battleType = 0;
|
|
this._isUnitLostEventShown = false;
|
|
this._attackFlow = createObject(AttackFlow);
|
|
this._battleObject = null;
|
|
},
|
|
|
|
_completeMemberData: function(attackParam) {
|
|
var result = EnterResult.CONTINUE;
|
|
|
|
this._checkAttack(attackParam);
|
|
|
|
if (CurrentMap.isCompleteSkipMode()) {
|
|
// 戦闘をスキップする場合は、この時点で戦闘を終わらす
|
|
this._finalizeAttack();
|
|
result = EnterResult.NOTENTER;
|
|
}
|
|
else {
|
|
this._playAttackStartSound();
|
|
this._battleObject.openBattleCycle(this);
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
_checkAttack: function() {
|
|
if (this._attackParam.attackStartType === AttackStartType.NORMAL) {
|
|
this._startNormalAttack();
|
|
}
|
|
else if (this._attackParam.attackStartType === AttackStartType.FORCE) {
|
|
this._startForceAttack();
|
|
}
|
|
},
|
|
|
|
_startNormalAttack: function() {
|
|
var infoBuilder = createObject(NormalAttackInfoBuilder);
|
|
var orderBuilder = createObject(NormalAttackOrderBuilder);
|
|
var attackInfo = infoBuilder.createAttackInfo(this._attackParam);
|
|
var attackOrder = orderBuilder.createAttackOrder(attackInfo);
|
|
|
|
return this._startCommonAttack(attackInfo, attackOrder);
|
|
},
|
|
|
|
_startForceAttack: function() {
|
|
var infoBuilder = createObject(ForceAttackInfoBuilder);
|
|
var orderBuilder = createObject(ForceAttackOrderBuilder);
|
|
var attackInfo = infoBuilder.createAttackInfo(this._attackParam);
|
|
var attackOrder = orderBuilder.createAttackOrder(attackInfo);
|
|
|
|
return this._startCommonAttack(attackInfo, attackOrder);
|
|
},
|
|
|
|
_startCommonAttack: function(attackInfo, attackOrder) {
|
|
this._setBattleTypeAndObject(attackInfo, attackOrder);
|
|
this._attackFlow.setAttackInfoAndOrder(attackInfo, attackOrder, this);
|
|
},
|
|
|
|
_finalizeAttack: function() {
|
|
this._attackFlow.finalizeAttack();
|
|
},
|
|
|
|
_doSkipAction: function() {
|
|
this._isBattleCut = true;
|
|
this._attackFlow.finalizeAttack();
|
|
this._battleObject.endBattle();
|
|
this._isBattleCut = false;
|
|
},
|
|
|
|
_setBattleTypeAndObject: function(attackInfo, attackOrder) {
|
|
var battleType = attackInfo.battleType;
|
|
var unitSrc = this._attackParam.unit;
|
|
var unitDest = this._attackParam.targetUnit;
|
|
|
|
if (battleType === BattleType.FORCEREAL) {
|
|
this._battleType = BattleType.REAL;
|
|
}
|
|
else if (battleType === BattleType.FORCEEASY) {
|
|
this._battleType = BattleType.EASY;
|
|
}
|
|
else {
|
|
// 強制戦闘でない同盟軍の戦闘は、isAllyBattleFixedがtrueを返す場合に簡易戦闘となる
|
|
if ((unitSrc.getUnitType() === UnitType.ALLY || unitDest.getUnitType() === UnitType.ALLY) && DataConfig.isAllyBattleFixed()) {
|
|
this._battleType = BattleType.EASY;
|
|
}
|
|
else {
|
|
this._battleType = battleType;
|
|
}
|
|
}
|
|
|
|
if (!DataConfig.isMotionGraphicsEnabled()) {
|
|
// リアル戦闘オフの場合は無条件に簡易戦闘
|
|
this._battleType = BattleType.EASY;
|
|
}
|
|
else {
|
|
if (this._isAnimeEmpty(unitSrc, unitDest)) {
|
|
// ユニットにアニメが設定されていない場合は簡易戦闘
|
|
this._battleType = BattleType.EASY;
|
|
}
|
|
}
|
|
|
|
if (this._battleType === BattleType.REAL) {
|
|
this._battleObject = createObject(RealBattle);
|
|
}
|
|
else {
|
|
this._battleObject = createObject(EasyBattle);
|
|
}
|
|
},
|
|
|
|
_isAnimeEmpty: function(unitSrc, unitDest) {
|
|
var animeSrc = BattlerChecker.findBattleAnimeFromUnit(unitSrc);
|
|
var animeDest = BattlerChecker.findBattleAnimeFromUnit(unitDest);
|
|
|
|
return animeSrc === null || animeDest === null;
|
|
},
|
|
|
|
_playAttackStartSound: function() {
|
|
if (this.isRealBattle()) {
|
|
// リアル戦闘では攻撃の開始音を再生
|
|
MediaControl.soundDirect('attackstart');
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
var BaseAttackInfoBuilder = defineObject(BaseObject,
|
|
{
|
|
createAttackInfo: function(attackParam) {
|
|
var picBackground;
|
|
var unitSrc = attackParam.unit;
|
|
var unitDest = attackParam.targetUnit;
|
|
var attackInfo = StructureBuilder.buildAttackInfo();
|
|
var mapInfo = root.getCurrentSession().getCurrentMapInfo();
|
|
var terrain = PosChecker.getTerrainFromPosEx(unitDest.getMapX(), unitDest.getMapY());
|
|
var terrainLayer = PosChecker.getTerrainFromPos(unitDest.getMapX(), unitDest.getMapY());
|
|
var direction = PosChecker.getSideDirection(unitSrc.getMapX(), unitSrc.getMapY(), unitDest.getMapX(), unitDest.getMapY());
|
|
|
|
// 背景画像を取得する。
|
|
// レイヤーが背景を持たない場合は下地から取得する。
|
|
picBackground = terrainLayer.getBattleBackgroundImage(mapInfo.getMapColorIndex());
|
|
if (picBackground === null) {
|
|
picBackground = terrain.getBattleBackgroundImage(mapInfo.getMapColorIndex());
|
|
}
|
|
|
|
attackInfo.unitSrc = unitSrc;
|
|
attackInfo.unitDest = unitDest;
|
|
attackInfo.terrainLayer = terrainLayer;
|
|
attackInfo.terrain = terrain;
|
|
attackInfo.picBackground = picBackground;
|
|
attackInfo.isDirectAttack = direction !== DirectionType.NULL;
|
|
attackInfo.isCounterattack = AttackChecker.isCounterattack(unitSrc, unitDest);
|
|
|
|
this._setMagicWeaponAttackData(attackInfo);
|
|
|
|
return attackInfo;
|
|
},
|
|
|
|
_setMagicWeaponAttackData: function(attackInfo) {
|
|
attackInfo.checkMagicWeaponAttack = function(unit) {
|
|
var result;
|
|
|
|
if (unit === this.unitSrc) {
|
|
result = this.isMagicWeaponAttackSrc;
|
|
}
|
|
else {
|
|
result = this.isMagicWeaponAttackDest;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
if (this._isMagicWeaponAttackAllowed(attackInfo)) {
|
|
attackInfo.isMagicWeaponAttackSrc = this._isMotionEnabled(attackInfo, attackInfo.unitSrc);
|
|
attackInfo.isMagicWeaponAttackDest = this._isMotionEnabled(attackInfo, attackInfo.unitDest);
|
|
}
|
|
},
|
|
|
|
_isMotionEnabled: function(attackInfo, unit) {
|
|
var midData = MotionIdControl.createEmptyMotionIdData();
|
|
|
|
midData.unit = unit;
|
|
midData.weapon = BattlerChecker.getRealBattleWeapon(unit);
|
|
midData.cls = BattlerChecker.getRealBattleClass(unit, midData.weapon);
|
|
midData.attackTemplateType = BattlerChecker.findAttackTemplateType(midData.cls, midData.weapon);
|
|
|
|
// 「戦士系」でない場合は、「魔法武器攻撃」という概念は存在しない
|
|
if (midData.attackTemplateType !== AttackTemplateType.FIGHTER) {
|
|
return false;
|
|
}
|
|
|
|
if (midData.weapon === null) {
|
|
return false;
|
|
}
|
|
|
|
// 装備武器の「武器エフェクト」において、「魔法武器」が設定されているか調べる
|
|
if (WeaponEffectControl.getAnime(unit, WeaponEffectAnime.MAGICWEAPON) === null) {
|
|
return false;
|
|
}
|
|
|
|
// 「魔法武器攻撃」のための「モーション情報」が設定されているか調べる
|
|
return this._getMagicWeaponAttackId(midData, false) !== MotionIdValue.NONE;
|
|
},
|
|
|
|
_getMagicWeaponAttackId: function(midData, isCritical) {
|
|
midData.isCritical = isCritical;
|
|
MotionIdControl.getMagicWeaponAttackId(midData);
|
|
|
|
return midData.id;
|
|
},
|
|
|
|
_isMagicWeaponAttackAllowed: function(attackInfo) {
|
|
if (root.getAnimePreference().isDirectMagicWeaponAttackAllowed()) {
|
|
// 直接でも間接でも「魔法武器攻撃」が考慮される
|
|
return true;
|
|
}
|
|
|
|
// 間接時のみ「魔法武器攻撃」が考慮される
|
|
return !attackInfo.isDirectAttack;
|
|
}
|
|
}
|
|
);
|
|
|
|
var NormalAttackInfoBuilder = defineObject(BaseAttackInfoBuilder,
|
|
{
|
|
createAttackInfo: function(attackParam) {
|
|
var attackInfo = BaseAttackInfoBuilder.createAttackInfo.call(this, attackParam);
|
|
|
|
attackInfo.battleType = EnvironmentControl.getBattleType();
|
|
|
|
attackInfo.isPosBaseAttack = true;
|
|
|
|
return attackInfo;
|
|
}
|
|
}
|
|
);
|
|
|
|
var ForceAttackInfoBuilder = defineObject(BaseAttackInfoBuilder,
|
|
{
|
|
createAttackInfo: function(attackParam) {
|
|
var forceBattleObject = attackParam.forceBattleObject;
|
|
var attackInfo = BaseAttackInfoBuilder.createAttackInfo.call(this, attackParam);
|
|
|
|
attackInfo.battleType = this._getBattleType(forceBattleObject);
|
|
|
|
attackInfo.forceBattleObject = forceBattleObject;
|
|
|
|
// 強制戦闘を示す値を設定
|
|
attackInfo.attackStartType = AttackStartType.FORCE;
|
|
|
|
// 経験値を考慮するかどうかを設定
|
|
attackInfo.isExperienceEnabled = forceBattleObject.isExperienceEnabled();
|
|
|
|
return attackInfo;
|
|
},
|
|
|
|
_getBattleType: function(forceBattleObject) {
|
|
var n, battleType;
|
|
|
|
n = forceBattleObject.getBattleType();
|
|
if (n === 0) {
|
|
battleType = BattleType.FORCEREAL;
|
|
}
|
|
else if (n === 1) {
|
|
battleType = BattleType.FORCEEASY;
|
|
}
|
|
else {
|
|
battleType = EnvironmentControl.getBattleType();
|
|
}
|
|
|
|
return battleType;
|
|
}
|
|
}
|
|
);
|
|
|
|
|
|
// 主要オブジェクトを外部から取得できるようにする
|
|
|
|
|
|
var AttackControl = {
|
|
_preAttack: null,
|
|
|
|
setPreAttackObject: function(preAttack) {
|
|
this._preAttack = preAttack;
|
|
},
|
|
|
|
isAttack: function() {
|
|
return this._preAttack !== null;
|
|
},
|
|
|
|
getPreAttackObject: function() {
|
|
return this._preAttack;
|
|
},
|
|
|
|
getCoreAttack: function() {
|
|
return this.getPreAttack().getCoreAttack();
|
|
},
|
|
|
|
getAttackParam: function() {
|
|
return this.getPreAttack().getAttackParam();
|
|
},
|
|
|
|
getAttackFlow: function() {
|
|
return this.getCoreAttack().getAttackFlow();
|
|
},
|
|
|
|
getBattleObject: function() {
|
|
return this.getCoreAttack().getBattleObject();
|
|
},
|
|
|
|
getAttackOrder: function() {
|
|
return this.getAttackFlow().getAttackOrder();
|
|
},
|
|
|
|
getAttackInfo: function() {
|
|
return this.getAttackFlow().getAttackInfo();
|
|
}
|
|
};
|
|
|
|
|
|
// リアル戦闘用補助オブジェクト
|
|
|
|
|
|
var BattlerChecker = {
|
|
findBattleAnimeFromUnit: function(unit) {
|
|
var weapon = this.getRealBattleWeapon(unit);
|
|
var cls = this.getRealBattleClass(unit, weapon);
|
|
|
|
return this.findBattleAnime(cls, weapon);
|
|
},
|
|
|
|
findBattleAnime: function(cls, weapon) {
|
|
var anime;
|
|
|
|
if (weapon !== null) {
|
|
return cls.getClassAnime(weapon.getWeaponCategoryType());
|
|
}
|
|
|
|
anime = cls.getClassAnime(WeaponCategoryType.PHYSICS);
|
|
if (anime !== null) {
|
|
return anime;
|
|
}
|
|
|
|
anime = cls.getClassAnime(WeaponCategoryType.SHOOT);
|
|
if (anime !== null) {
|
|
return anime;
|
|
}
|
|
|
|
anime = cls.getClassAnime(WeaponCategoryType.MAGIC);
|
|
if (anime !== null) {
|
|
return anime;
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
findAttackTemplateTypeFromUnit: function(unit) {
|
|
var weapon = BattlerChecker.getRealBattleWeapon(unit);
|
|
var cls = BattlerChecker.getRealBattleClass(unit, weapon);
|
|
|
|
return this.findAttackTemplateType(cls, weapon);
|
|
},
|
|
|
|
findAttackTemplateType: function(cls, weapon) {
|
|
var classMotionFlag;
|
|
|
|
if (weapon !== null) {
|
|
return weapon.getWeaponCategoryType();
|
|
}
|
|
|
|
classMotionFlag = cls.getClassMotionFlag();
|
|
|
|
if (classMotionFlag & ClassMotionFlag.FIGHTER) {
|
|
return AttackTemplateType.FIGHTER;
|
|
}
|
|
|
|
if (classMotionFlag & ClassMotionFlag.ARCHER) {
|
|
return AttackTemplateType.ARCHER;
|
|
}
|
|
|
|
if (classMotionFlag & ClassMotionFlag.MARGE) {
|
|
return AttackTemplateType.MARGE;
|
|
}
|
|
|
|
return 0;
|
|
},
|
|
|
|
getRealBattleWeapon: function(unit) {
|
|
// 本来の武器とは異なる武器でリアル戦闘を行いたい場合は、このメソッドで調整する
|
|
return ItemControl.getEquippedWeapon(unit);
|
|
},
|
|
|
|
getRealBattleClass: function(unit, weapon) {
|
|
// 本来のクラスとは異なるクラスでリアル戦闘を行いたい場合は、このメソッドで調整する
|
|
return unit.getClass();
|
|
}
|
|
};
|
|
|
|
var BattlerPosChecker = {
|
|
getRealInitialPos: function(motionParam, isSrc, order) {
|
|
var moveMotionId;
|
|
|
|
if (!root.getAnimePreference().isMoveMotionPosInherited()) {
|
|
// 移動モーションの位置を引き継がない場合は、既定の位置が使用される
|
|
return this._getDefaultPos(motionParam);
|
|
}
|
|
|
|
moveMotionId = this._getMoveId(motionParam, order);
|
|
if (moveMotionId === MotionIdValue.NONE) {
|
|
// 戦闘するユニット両方が移動を行わない場合は、既定の位置が使用される
|
|
return this._getDefaultPos(motionParam);
|
|
}
|
|
|
|
// 移動モーションのIDをベースに位置を求める
|
|
return this._getAbsolutePos(motionParam, moveMotionId);
|
|
},
|
|
|
|
_getDefaultPos: function(motionParam) {
|
|
var size = Miscellaneous.getFirstKeySpriteSize(motionParam.animeData, motionParam.motionId);
|
|
var boundaryWidth = root.getAnimePreference().getBoundaryWidth();
|
|
var boundaryHeight = root.getAnimePreference().getBoundaryHeight();
|
|
var x = GraphicsFormat.BATTLEBACK_WIDTH - boundaryWidth;
|
|
var y = GraphicsFormat.BATTLEBACK_HEIGHT - boundaryHeight - size.height;
|
|
|
|
if (!motionParam.isRight) {
|
|
x = boundaryWidth - size.width;
|
|
}
|
|
|
|
return createPos(x, y);
|
|
},
|
|
|
|
_getAbsolutePos: function(motionParam, moveMotionId) {
|
|
var animeData = motionParam.animeData;
|
|
var frameIndex = 0;
|
|
var spriteIndex = this._getSpriteIndexFromSpriteType(animeData, moveMotionId, frameIndex, SpriteType.KEY);
|
|
var x = animeData.getSpriteX(moveMotionId, frameIndex, spriteIndex);
|
|
var y = animeData.getSpriteY(moveMotionId, frameIndex, spriteIndex);
|
|
|
|
if (!motionParam.isRight) {
|
|
x = (GraphicsFormat.BATTLEBACK_WIDTH - GraphicsFormat.MOTION_WIDTH) - x;
|
|
}
|
|
|
|
return createPos(x, y);
|
|
},
|
|
|
|
_getMoveId: function(motionParam, order) {
|
|
var i;
|
|
var count = 0;
|
|
var moveMotionId = MotionIdValue.NONE;
|
|
|
|
for (;;) {
|
|
if (order.getMoveId() !== MotionIdValue.NONE && order.getActiveUnit() === motionParam.unit) {
|
|
moveMotionId = order.getMoveId();
|
|
break;
|
|
}
|
|
|
|
if (!order.nextOrder()) {
|
|
break;
|
|
}
|
|
count++;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
order.prevOrder();
|
|
}
|
|
|
|
return moveMotionId;
|
|
},
|
|
|
|
_getSpriteIndexFromSpriteType: function(animeData, motionId, frameIndex, spriteType) {
|
|
var i;
|
|
var count = animeData.getSpriteCount(motionId, frameIndex);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (animeData.getSpriteType(motionId, frameIndex, i) === spriteType) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
};
|