// 半即时战斗脚本
// 作者:xsrong
// ---------------------------------------------------
// 插件简介:
// 启用该脚本后,战斗系统将改变为蓄槽模式的半即时战斗。
// ---------------------------------------------------
// 使用注意:
// ※本插件为战斗每个成员新增了cp值,cp值按照该成员的敏捷值进行增长,
// ※我方成员的cp值增长到10000后弹出战斗选项,敌方成员cp值增长至10000之后采取行动。
// ※可以为每个技能和物品设定单独的cp cost,使用该技能和物品的话会扣除相应的cp。
// ※设定方法:在物品或技能的备注栏备注<CPCOST xxxxx>。xxxxx最小为0,最大为10000。
// ※未设定物品或技能的cp cost则默认为10000。
// ※逃跑失败固定扣除10000cp。
//
// ※本插件更改了遇敌时决定先手和被袭击的条件,
// ※使得明雷遇敌(在事件中呼叫战斗处理)也有几率触发先手和被袭击。
// ※另外需要设置以下三个全局开关用以控制先手和被袭击:
// ※在preemptiveSwitch储存的开关id打开的情况下必定先手
// ※在surpriseSwitch储存的开关id打开的情况下必定被袭击
// ※在noPreemptiveAndSurprise储存的开关id打开的情况下不会触发先手和被袭击
// ※默认1号开关打开情况下每次战斗必先手,2号开关打开情况下必被偷袭,3号开关打开情况下不会发生先手或被偷袭。
//
// ※本插件为每个战斗成员新增了_turnCount属性,用以记录战斗成员的回合数。
//
// ※本插件新增了以下两个全局函数用以设置战斗事件的发生条件:
// ※currentActionBattler() 调用该函数会返回当前正在行动的战斗成员
// ※currentActionBattlerTurnCount() 调用该函数会返回当前正在行动的战斗成员的回合数
// ※本插件向Game_Battler类新增了isCurrentActionBattler()函数,调用该方法会返回某Game_Battler实例是否是当前正在行动的成员的布尔值。
// ※通过上面三个函数,可以在战斗事件中精确控制己方或地方成员每回合的动作。
// ※具体设置方法可以参考范例工程。
//
// ※本插件更改了战斗中状态图标的显示,战斗中的状态图标右上角显示该状态有效的剩余回合数。
// ※每个战斗成员的状态剩余回合数是独立控制的。该成员行动之后,该成员身上的状态会立即更新。
// ---------------------------------------------------
// 设置战斗成员的初始cp
Game_Battler.prototype._cp = 0;
// 控制每次战斗必先手的开关id
var preemptiveSwitch = 1;
// 控制每次战斗必备偷袭的开关id
var surpriseSwitch = 2;
// 注:上面两个开关同时打开时,每次战斗必先手
// 控制战斗先手和被偷袭无效的开关id
var noPreemptiveAndSurprise = 3;
// ---------------------------------------------------
// 绘制战斗成员行动槽的窗口
// ---------------------------------------------------
function Window_CPBar() {
this.initialize.apply(this, arguments)
};
Window_CPBar.prototype = Object.create(Window_Base.prototype);
Window_CPBar.prototype.constructor = Window_CPBar;
Window_CPBar.prototype.initialize = function (x, y, w, h) {
Window_Base.prototype.initialize.call(this, x, y, w, h);
this.opacity = 0; // 将窗口背景和框架透明化
this._actorFaceBitmaps = []; // 保存行动槽上角色头像的数组
this._enemyFaceBitmaps = []; // 保存行动槽上敌人头像的数组
this.createActorCPBarFaces();
this.createEnemyCPBarFaces();
};
Window_CPBar.prototype.refresh = function() {
this.contents.clear();
this.drawCPBar(this.x + 20, this.y, this.width - 80);
this.drawCPBarFaces()
};
Window_CPBar.prototype.drawCPBar = function(x, y, width) {
width = width || 186;
var color1 = 'black'; // 行动槽左端颜色
var color2 = 'grey'; // 行动槽右端颜色
this.drawGauge(x, y, width, 1, color1, color2);
};
Window_CPBar.prototype.createActorCPBarFace = function(faceName) {
var bitmap = ImageManager.loadFace(faceName);
this._actorFaceBitmaps.push(bitmap);
}
Window_CPBar.prototype.createActorCPBarFaces = function() {
actors = $gameParty.members();
for (var i = 0; i < actors.length; i++) {
this.createActorCPBarFace(actors[i].faceName());
}
}
Window_CPBar.prototype.createEnemyCPBarFace = function(battlerName) {
var bitmap = ImageManager.loadEnemy(battlerName);
this._enemyFaceBitmaps.push(bitmap);
}
Window_CPBar.prototype.createEnemyCPBarFaces = function() {
enemies = $gameTroop.members();
for (var i = 0; i < enemies.length; i++) {
this.createEnemyCPBarFace(enemies[i].enemy().battlerName);
}
}
Window_CPBar.prototype.drawActorCPBarFaces = function() {
actors = $gameParty.members();
for (var i = 0; i < actors.length; i++) {
if (actors[i].isAlive()) {
var pw = Window_Base._faceWidth;
var ph = Window_Base._faceHeight;
var rate = actors[i]._cp / 10000;
rate = Math.min(rate, 1);
var dx = rate * (this.width - 95);
var dy = 0;
var sx = actors[i].faceIndex() % 4 * pw;
var sy = Math.floor(actors[i].faceIndex() / 4) * ph;
this.contents.blt(this._actorFaceBitmaps[i], sx, sy, pw, ph, dx, dy, 30, 30);
}
}
}
Window_CPBar.prototype.drawEnemyCPBarFaces = function() {
enemies = $gameTroop.members();
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].isAlive()) {
var pw = this._enemyFaceBitmaps[i]._image.width;
var ph = this._enemyFaceBitmaps[i]._image.height;
var rate = enemies[i]._cp / 10000;
rate = Math.min(rate, 1);
var dx = rate * (this.width - 95);
var dy = 0;
var sx = 0;
var sy = 0;
this.contents.blt(this._enemyFaceBitmaps[i], sx, sy, pw, ph, dx, dy, 30, 30);
}
}
}
Window_CPBar.prototype.drawCPBarFaces = function() {
this.drawEnemyCPBarFaces();
this.drawActorCPBarFaces();
}
// ---------------------------------------------------
// 修改战斗场景
// ---------------------------------------------------
xsrongSceneBattleCreateAllWindows = Scene_Battle.prototype.createAllWindows;
Scene_Battle.prototype.createAllWindows = function() {
xsrongSceneBattleCreateAllWindows.call(this);
this.createCPBarWindow(); // 向战斗场景中加入行动槽
};
Scene_Battle.prototype.createCPBarWindow = function() {
this._cpBarWindow = new Window_CPBar(0, 0, Graphics.boxWidth, 72)
this._spriteset.addChild(this._cpBarWindow)
};
Scene_Battle.prototype.updateCPBarWindow = function() {
var battlers = $gameParty.members().concat($gameTroop.members());
battlers.forEach(function(b) {
if (b.isAlive()) {
b._cp += b.agi; // 战斗成员cp值的增加量为该成员的敏捷度
}
});
this._cpBarWindow.refresh();
};
// 向战斗场景中的角色命令窗口增加逃跑选项
xsrongSceneBattleCreateActorCommandWindow = Scene_Battle.prototype.createActorCommandWindow;
Scene_Battle.prototype.createActorCommandWindow = function() {
this._actorCommandWindow = new Window_ActorCommand();
this._actorCommandWindow.setHandler('attack', this.commandAttack.bind(this));
this._actorCommandWindow.setHandler('skill', this.commandSkill.bind(this));
this._actorCommandWindow.setHandler('guard', this.commandGuard.bind(this));
this._actorCommandWindow.setHandler('item', this.commandItem.bind(this));
this._actorCommandWindow.setHandler('escape', this.commandEscape.bind(this));
this.addWindow(this._actorCommandWindow);
};
xsrongSceneBattleCommandEscape = Scene_Battle.prototype.commandEscape;
Scene_Battle.prototype.commandEscape = function() {
BattleManager.processEscape();
};
BattleManager.processEscape = function() {
$gameParty.performEscape();
SoundManager.playEscape();
var success = this._preemptive ? true : (Math.random() < this._escapeRatio);
if (success) {
this.displayEscapeSuccessMessage();
this._escaped = true;
this.processAbort();
} else {
this.actor()._cp -= 10000; // 逃跑失败扣除10000点cp
this.actor().onTurnEnd(); // 逃跑失败更新该角色身上的状态
this.displayEscapeFailureMessage();
this._escapeRatio += 0.1;
$gameParty.clearActions();
this._phase = 'xsrong_wait'; // 逃跑失败继续等待行动
this.xsrongWait();
}
return success;
};
xsrongBattleManagerUpdate = BattleManager.update;
BattleManager.update = function() {
if (!this.isBusy() && !this.updateEvent()) {
switch (this._phase) {
case 'start':
this.xsrongStart();
break;
case 'turn':
this.updateTurn();
break;
case 'action':
this.updateAction();
break;
case 'turnEnd':
this.updateTurnEnd();
break;
case 'battleEnd':
this.updateBattleEnd();
break;
case 'xsrong_wait': // 等待行动槽涨满
this.xsrongWait();
break;
case 'enemy_action': // 等待敌人行动
this.updateTurn();
break;
};
}
};
xsrongBattleManagerUpdateEvent = BattleManager.updateEvent;
BattleManager.updateEvent = function() {
switch (this._phase) {
case 'start':
case 'turn':
case 'enemy_action':
if (this.isActionForced()) {
this.processForcedAction();
return true;
} else {
return this.updateEventMain();
}
}
return this.checkAbort();
};
BattleManager.processForcedAction = function() {
if (this._actionForcedBattler) {
this._subject = this._actionForcedBattler;
this._actionForcedBattler = null;
this.startAction();
this._subject.removeCurrentAction();
this._subject._turnCount++; // 战斗事件中强制战斗行动后增加该成员的回合数
this._subject.onTurnEnd(); // 战斗事件中强制战斗行动后更新该成员身上的状态
}
};
xsrongBattleManagerMakeActionOrders = BattleManager.makeActionOrders;
BattleManager.makeActionOrders = function() {
var battlers = [];
battlers = battlers.concat($gameParty.members()).concat($gameTroop.members())
this._actionBattlers = battlers;
};
// 设置战斗开始时每个战斗成员的cp
BattleManager.setupMemberCP = function() {
if (this._surprise) {
$gameTroop.members().forEach(function(enemy) {
enemy._cp = 10000 - Math.floor(Math.random()*5) * 10; // 被偷袭的场合,所有敌人的cp直接涨满
});
} else if (this._preemptive) {
$gameParty.members().forEach(function(actor){
actor._cp = 10000 - actor.agi; // 我方先手的场合,所有我方队员的cp直接涨满
});
} else {
for (var i = 0; i < this._actionBattlers.length; i++) {
randNum = Math.floor(Math.random()*20) * 50;
this._actionBattlers[i]._cp = this._actionBattlers[i].agi * 10 + randNum; // 没有先手和被偷袭的场合,随机设置所有成员的初始cp
};
}
}
BattleManager.setupMemberTurnCount = function() {
battlers = this._actionBattlers;
battlers.forEach(function(battler) {
battler._turnCount = 1; // 设置每个成员的初始回合数
})
}
BattleManager.xsrongStart = function() {
this.makeActionOrders();
this.setupMemberCP();
this.setupMemberTurnCount();
this._phase = 'xsrong_wait'; // 进入战斗后开始等待行动槽涨满
};
BattleManager.xsrongWait = function() {
for (var i = 0; i < $gameParty.members().length; i++) {
var actor = $gameParty.members()[i];
if (actor._cp >= 10000) {
this._phase = "turn"
this._subject = actor;
this._actorIndex = $gameParty.members().indexOf(actor);
if (!this.updateEvent()) {
this._phase = "input"; // 角色没有被强制行动的话,输入战斗指令
actor.makeActions();
} else {
this.processForcedAction(); // 角色被强制行动的话,无视已输入的指令,执行强制行动
}
break;
}
};
for (var j = 0; j < $gameTroop.members().length; j++) {
var enemy = $gameTroop.members()[j];
if (enemy._cp >= 10000) {
$gameTroop.increaseTurn();
this._phase = "enemy_action";
enemy.makeActions();
this._subject = enemy;
break;
}
}
SceneManager._scene.updateCPBarWindow();
};
xsrongBattleManagerSelectNextCommand = BattleManager.selectNextCommand;
BattleManager.selectNextCommand = function() {
do {
this.startTurn();
break;
} while (!this.actor().canInput());
};
xsrongBattleManagerUpdateTurnEnd = BattleManager.updateTurnEnd;
BattleManager.updateTurnEnd = function() {
this.xsrongWait(); // 一个战斗成员的行动结束后,继续等待行动槽涨满
};
xsrongBattleManagerOnEncounter = BattleManager.onEncounter
BattleManager.onEncounter = function() {
xsrongBattleManagerOnEncounter.call(this);
if ($gameSwitches._data[preemptiveSwitch]) {
this._preemptive = true; // 强制先手的开关打开时,战斗强制先手
}
if (!$gameSwitches._data[preemptiveSwitch] && $gameSwitches._data[surpriseSwitch]) {
this._surprise = true; // 强制被偷袭的开关打开时,战斗强制被偷袭
}
if ($gameSwitches._data[noPreemptiveAndSurprise]) {
this._preemptive = false; // 先手和被偷袭无效的开关打开时,先手和被偷袭无效
this._surprise = false;
}
};
xsrongBattleManagerProcessTurn = BattleManager.processTurn
BattleManager.processTurn = function() {
var subject = this._subject;
var action = subject.currentAction();
if (action) {
action.prepare();
if (action.isValid()) {
this.startAction();
}
subject.removeCurrentAction();
subject._turnCount++ ; // 行动结束后增加战斗成员的回合数
subject.onTurnEnd(); // 行动结束后更新战斗成员身上的状态
} else {
subject.onAllActionsEnd();
this.refreshStatus();
this._logWindow.displayAutoAffectedStatus(subject);
this._logWindow.displayCurrentState(subject);
this._logWindow.displayRegeneration(subject);
this._subject = this.getNextSubject();
}
};
xsrongBattleManagerEndTurn = BattleManager.endTurn
BattleManager.endTurn = function() {
this._phase = 'turnEnd';
this._preemptive = false;
this._surprise = false;
this.allBattleMembers().forEach(function(battler) { // 取消了在这里更新战斗成员状态的代码
this.refreshStatus();
this._logWindow.displayAutoAffectedStatus(battler);
this._logWindow.displayRegeneration(battler);
}, this);
};
// 读取技能和物品需要的cp
Game_BattlerBase.prototype.skillCpCost = function(skill) {
var pat = /<CPCOST\s\d+>/;
var str = pat.exec(skill.note);
var cpCost;
if (str) {
cpCost = parseInt(str.input.split(" ")[1]);
cpCost = Math.min(cpCost, 10000)
cpCost = Math.max(cpCost, 0)
} else {
cpCost = 10000;
}
return cpCost;
};
Game_Battler.prototype.useItem = function(item) {
if (DataManager.isSkill(item)) {
this.paySkillCost(item);
} else if (DataManager.isItem(item)) {
this.consumeItem(item);
if ($gameParty.inBattle()) { // 在战斗中使用物品会被扣除相应的cp
var cpCost = this.skillCpCost(item);
this._cp -= cpCost;
}
}
};
xsrongGameBattlerBasePaySkillCost = Game_BattlerBase.prototype.paySkillCost;
Game_BattlerBase.prototype.paySkillCost = function(skill) {
xsrongGameBattlerBasePaySkillCost.call(this, skill);
if ($gameParty.inBattle()) {
this._cp -= this.skillCpCost(skill); // 在战斗中使用技能会被扣除相应的cp
}
};
xsrongGameBattlerBaseDie = Game_BattlerBase.prototype.die
Game_BattlerBase.prototype.die = function() {
xsrongGameBattlerBaseDie.call(this);
this._cp = 0; // 角色倒下时cp归零
};
xsrongWindowActorCommandMakeCommandList = Window_ActorCommand.prototype.makeCommandList;
Window_ActorCommand.prototype.makeCommandList = function() {
if (this._actor) {
this.addAttackCommand();
this.addSkillCommands();
this.addGuardCommand();
this.addItemCommand();
this.addEscapeCommand();
}
};
Window_ActorCommand.prototype.addEscapeCommand = function() {
this.addCommand(TextManager.escape, 'escape', BattleManager.canEscape());
};
xsrongGameInterpreterCommand301 = Game_Interpreter.prototype.command301;
Game_Interpreter.prototype.command301 = function() {
if (!$gameParty.inBattle()) {
var troopId;
if (this._params[0] === 0) {
troopId = this._params[1];
} else if (this._params[0] === 1) {
troopId = $gameVariables.value(this._params[1]);
} else {
troopId = $gamePlayer.makeEncounterTroopId();
}
if ($dataTroops[troopId]) {
BattleManager.setup(troopId, this._params[2], this._params[3]);
BattleManager.onEncounter(); // 采用明雷遇敌时增加偷袭和被偷袭功能
BattleManager.setEventCallback(function(n) {
this._branch[this._indent] = n;
}.bind(this));
$gamePlayer.makeEncounterCount();
SceneManager.push(Scene_Battle);
}
}
return true;
};
xsrongDataManagerSetupBattleTest = DataManager.setupBattleTest;
DataManager.setupBattleTest = function() {
this.createGameObjects();
$gameParty.setupBattleTest();
BattleManager.setup($dataSystem.testTroopId, true, false);
BattleManager.onEncounter(); // 战斗测试中增加偷袭和被偷袭功能
BattleManager.setBattleTest(true);
BattleManager.playBattleBgm();
};
Window_Base.prototype.drawActorIcons = function(actor, x, y, width) {
width = width || 144;
var icons = actor.allIcons().slice(0, Math.floor(width / Window_Base._iconWidth));
var states = actor._states.filter(function(s){
return $dataStates[s].iconIndex > 0;
})
var text;
for (var i = 0; i < icons.length; i++) { // 在角色状态图标上增加剩余回合数
this.drawIcon(icons[i], x + (Window_Base._iconWidth + 8) * i, y + 2);
if (i < states.length) {
stateId = states[i]
if ($dataStates[stateId].autoRemovalTiming == 1) {
text = actor._stateTurns[stateId] // 能够自动解除的状态显示剩余回合数
} else {
text = "∞" // 不能自动解除的状态显示剩余回合数无限
}
} else {
text = actor._buffTurns[i - states.length] // 显示角色身上buff的剩余回合数
}
this.drawIconText(text, x + (Window_Base._iconWidth + 8) * i + 24, y);
}
};
Window_Base.prototype.drawIconText = function(text, x, y) {
var bitmap = new Bitmap(this.width, this.height);
bitmap.drawCircle(16, 16, 16, 'red');
bitmap.drawText(text, 0, 0, 32, 32, 'center');
this.contents.blt(bitmap, 0, 0, 32, 32, x, y, 12, 12);
};
Sprite_Enemy.prototype.updateStateTurnSpriteText = function() {
var states = this._enemy._states.filter(function(s) {
return $dataStates[s].iconIndex > 0;
});
var text;
if (this._stateIconSprite._animationIndex < states.length) { // 在敌人状态图标上增加剩余回合数
if ($dataStates[this._enemy._states[this._stateIconSprite._animationIndex]].autoRemovalTiming == 1) {
text = this._enemy._stateTurns[this._enemy._states[this._stateIconSprite._animationIndex]]; // 能够自动解除的状态显示剩余回合数
} else {
text = "∞"; // 不能自动解除的状态显示剩余回合数无限
}
} else {
text = this._enemy._buffTurns[this._stateIconSprite._animationIndex - states.length]; // 显示敌人身上buff的剩余回合数
}
this.drawStateTurnSprite(text);
if (states.length > 0) {
this._stateTurnSprite.opacity = 255
} else {
this._stateTurnSprite.opacity = 0
}
};
Sprite_Enemy.prototype.update = function() {
Sprite_Battler.prototype.update.call(this);
if (this._enemy) {
this.updateEffect();
this.updateStateSprite();
this._stateTurnSprite.y = this._stateIconSprite.y - 20
this._stateTurnSprite.x = 8
this.updateStateTurnSpriteText();
}
};
Sprite_Enemy.prototype.createStateTurnSprite = function() {
var bitmap = new Bitmap(12, 12)
bitmap.outlineWidth = 0;
bitmap.fontSize = 10;
sp = new Sprite(bitmap);
this._stateTurnSprite = sp;
this.addChild(this._stateTurnSprite);
};
Sprite_Enemy.prototype.drawStateTurnSprite = function(text) {
bitmap = this._stateTurnSprite.bitmap
bitmap.drawCircle(6, 6, 6, 'red');
bitmap.drawText(text, 0, 0, 12, 12, 'center');
};
Sprite_Enemy.prototype.initMembers = function() {
Sprite_Battler.prototype.initMembers.call(this);
this._enemy = null;
this._appeared = false;
this._battlerName = '';
this._battlerHue = 0;
this._effectType = null;
this._effectDuration = 0;
this._shake = 0;
this.createStateIconSprite();
this.createStateTurnSprite();
};
// 判断某个Game_Battler实例对象是否正在行动
Game_Battler.prototype.isCurrentActionBattler = function() {
return currentActionBattler() === this;
}
// 返回正在行动的战斗成员的回合数
currentActionBattlerTurnCount = function() {
var battler = currentActionBattler();
if (battler) {
return battler._turnCount;
}
}
// 返回正在行动的战斗成员。如没有正在行动的战斗成员,则返回null
currentActionBattler = function() {
if (BattleManager._subject) {
return BattleManager._subject;
} else if (BattleManager.actor()) {
return BattleManager.actor()
} else {
return null
}
}