じ☆ve冰风 发表于 2024-3-4 10:06:34

自制半即时战斗系统

发一个自制的半即时战斗系统,长相就是下面图片的样子……
不太会用的也可以参考范例工程~

注意:此脚本未经过严格的测试,可能发生BUG或与其它脚本不兼容的情况。
如有问题可以回帖或私信。

JAVASCRIPT 代码
// 半即时战斗脚本
// 作者:xsrong
// ---------------------------------------------------
// 插件简介:
// 启用该脚本后,战斗系统将改变为蓄槽模式的半即时战斗。
// ---------------------------------------------------
// 使用注意:
// ※本插件为战斗每个成员新增了cp值,cp值按照该成员的敏捷值进行增长,
// ※我方成员的cp值增长到10000后弹出战斗选项,敌方成员cp值增长至10000之后采取行动。
// ※可以为每个技能和物品设定单独的cp cost,使用该技能和物品的话会扣除相应的cp。
// ※设定方法:在物品或技能的备注栏备注。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.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.enemy().battlerName);
}
}

Window_CPBar.prototype.drawActorCPBarFaces = function(){
actors = $gameParty.members();
for(var i = 0; i < actors.length; i++){
    if(actors.isAlive()){
      var pw = Window_Base._faceWidth;
      var ph = Window_Base._faceHeight;
      var rate = actors._cp / 10000;
      rate = Math.min(rate, 1);
      var dx = rate * (this.width - 95);
      var dy = 0;
      var sx = actors.faceIndex() % 4 * pw;
      var sy = Math.floor(actors.faceIndex() / 4) * ph;
      this.contents.blt(this._actorFaceBitmaps, 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.isAlive()){
      var pw = this._enemyFaceBitmaps._image.width;
      var ph =this._enemyFaceBitmaps._image.height;
      var rate = enemies._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, 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();
          returntrue;
      }else{
          returnthis.updateEventMain();
      }
}
returnthis.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直接涨满
    });
}elseif(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._cp = this._actionBattlers.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();
    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();
    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){
    this._preemptive = true;                                  // 强制先手的开关打开时,战斗强制先手
}
if(!$gameSwitches._data && $gameSwitches._data){
    this._surprise = true;                                    // 强制被偷袭的开关打开时,战斗强制被偷袭
}
if($gameSwitches._data){
    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 = //;
var str = pat.exec(skill.note);
var cpCost;
if(str){
      cpCost = parseInt(str.input.split(" "));
      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);
}elseif(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){
          troopId = this._params;
      }elseif(this._params === 1){
          troopId = $gameVariables.value(this._params);
      }else{
          troopId = $gamePlayer.makeEncounterTroopId();
      }
      if($dataTroops){
          BattleManager.setup(troopId, this._params, this._params);
          BattleManager.onEncounter();                         // 采用明雷遇敌时增加偷袭和被偷袭功能
          BattleManager.setEventCallback(function(n){
            this._branch = n;
          }.bind(this));
          $gamePlayer.makeEncounterCount();
          SceneManager.push(Scene_Battle);
      }
}
returntrue;
};

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.iconIndex > 0;
})
var text;
for(var i = 0; i < icons.length; i++){                  // 在角色状态图标上增加剩余回合数
      this.drawIcon(icons, x + (Window_Base._iconWidth + 8) * i, y + 2);
      if(i < states.length){
          stateId = states
          if($dataStates.autoRemovalTiming == 1){
            text = actor._stateTurns             // 能够自动解除的状态显示剩余回合数
          }else{
            text = "∞"                                    // 不能自动解除的状态显示剩余回合数无限
          }
      }else{
          text = actor._buffTurns      // 显示角色身上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.iconIndex > 0;
});
var text;
if(this._stateIconSprite._animationIndex < states.length){      // 在敌人状态图标上增加剩余回合数
      if($dataStates].autoRemovalTiming == 1){
      text = this._enemy._stateTurns];   // 能够自动解除的状态显示剩余回合数
      }else{
      text = "∞";                                                   // 不能自动解除的状态显示剩余回合数无限
      }
}else{
      text = this._enemy._buffTurns;    // 显示敌人身上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;
}elseif(BattleManager.actor()){
    return BattleManager.actor()
}else{
    returnnull
}
}


             本帖来自P1论坛作者xsrong2,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=479546若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。
页: [1]
查看完整版本: 自制半即时战斗系统