/*:
@plugindesc [1.0] Allows you to set states to be applied based on arbitrary conditions.
@author Solarflare Software
@help
Use the following note tag to turn a state into a passive state:
<activeif:true> (states)
This state is automatically added or removed based on the given condition.
As with a damage formula, the actor can be referenced as a.
Game variables are also available as v and switches as s.
The state object itself can be accessed as state.
*/
var Imported = Imported || {};
(function() {
var conditionalStates = [];
var old_startup = Scene_Boot.prototype.start;
Scene_Boot.prototype.start = function() {
old_startup.call(this);
for(var i = 1; i < $dataStates.length; i++) {
if($dataStates[i].meta.activeif)
conditionalStates.push(i);
}
};
Game_BattlerBase.prototype.isStateConditionallyActive = function(stateId) {
if(this.isStateResist(stateId)) return false;
var state = $dataStates[stateId];
if(!state) return false;
var cond = state.meta.activeif;
if(cond) {
let locals = {
state: state,
a: this,
};
try {
return !!Utils.eval(cond, locals);
} catch(e) {}
}
return false;
};
const old_globalUpdate = Scene_Base.prototype.update;
Scene_Base.prototype.update = function() {
old_globalUpdate.call(this);
$gameParty.refreshPassiveStates();
$gameTroop.refreshPassiveStates();
};
const old_isStateAddable = Game_Battler.prototype.isStateAddable;
const old_removeState = Game_Battler.prototype.removeState;
Game_Battler.prototype.isStateAddable = function(state) {
if(conditionalStates.includes(state))
return this.isStateConditionallyActive(state);
return old_isStateAddable.call(this, state);
};
Game_Battler.prototype.removeState = function(state) {
if(conditionalStates.includes(state) && this.isStateConditionallyActive(state))
return;
old_removeState.call(this, state);
};
Game_Battler.prototype.requestPassiveStateRefresh = function() {
this._needsPassiveStateUpdate = true;
this.friendsUnit()._needsPassiveStateUpdate = true;
};
Game_Battler.prototype.refreshPassiveStates = function() {
this._needsPassiveStateUpdate = false;
for(let i = 0; i < conditionalStates.length; i++) {
let stateId = conditionalStates[i];
if(this.isStateConditionallyActive(stateId))
this.addState(stateId);
else this.removeState(stateId);
}
};
// Should also override isStateAddable to return false if the condition is not satisfied, and removeState to not remove it if the condition is still satisfied.
Game_Unit.prototype.requestPassiveStateRefresh = function() {
this._needsPassiveStateUpdate = true;
this.members().forEach(who => who.requestPassiveStateRefresh());
};
Game_Unit.prototype.refreshPassiveStates = function() {
if(!this._needsPassiveStateUpdate) return;
this._needsPassiveStateUpdate = false;
this.members().forEach(function(who) {
if(who._needsPassiveStateUpdate)
who.refreshPassiveStates();
});
};
Game_Troop.prototype.refreshPassiveStates = function() {
if(this.inBattle()) Game_Unit.prototype.refreshPassiveStates.call(this);
};
Game_Party.prototype.refreshPassiveStates = function() {
// Refresh on all members, even in battle
var inBattle = this.inBattle();
this._inBattle = false;
Game_Unit.prototype.refreshPassiveStates.call(this);
this._inBattle = inBattle;
};
const updateParty = () => $gameParty.requestPassiveStateRefresh();
const updateAll = () => {$gameParty.requestPassiveStateRefresh(); $gameTroop.inBattle() && $gameTroop.requestPassiveStateRefresh()};
const refreshMethods = [
{
class: Game_Battler,
methods: ['onAllActionsEnd', 'onTurnEnd', 'onBattleStart', 'onBattleEnd', 'refresh'],
},
{
class: Game_Actor,
check: (self, skill) => self.isLearnedSkill(skill),
methods: ['learnSkill', 'forgetSkill'],
},
{
class: Game_Enemy,
methods: ['appear'],
},
{
class: Game_Party,
methods: ['gainGold', 'gainItem'],
},
{
class: Game_Player,
update: updateParty,
methods: ['refresh'],
},
{
class: Game_Player,
check: (self) => self.isInVehicle(),
update: updateParty,
methods: ['getOnOffVehicle'],
},
{
class: Game_Event,
update: updateParty,
methods: ['refresh'],
},
{
class: Game_CharacterBase,
update: updateParty,
methods: ['increaseSteps', 'setPosition', 'copyPosition'],
},
{
class: Game_Switches,
update: updateAll,
methods: ['onChange'],
},
{
class: Game_Variables,
update: updateAll,
methods: ['onChange'],
},
{
class: Game_SelfSwitches,
update: updateAll,
methods: ['onChange'],
},
];
if(Imported.TH_SelfVariables) {
refreshMethods.push({
class: Game_SelfVariables,
update: updateAll,
methods: ['onChange'],
});
}
for(let cls of refreshMethods) {
let proto = cls.static ? cls.class : cls.class.prototype;
for(let fcn of cls.methods) {
let old = Utils.makeAliasProxy(cls.class, fcn);
let check = cls.check ? cls.check : (self) => {};
let update = cls.update ? cls.update : (self) => self.requestPassiveStateRefresh();
proto[fcn] = function() {
var before = check(this);
old(this, ...arguments);
if(before === undefined || before != check(this, ...arguments)) {
update(this);
}
};
}
}
})()