Unlocking Character Poses
One thing that was annoying about chrono engine was the limitation on character poses. By default it parses the first of a given tag in a character image filename, so having a character with nonstandard frames locks all the poses to be identical.
For instance, if you had $Harold(f6)(f2) as your protagonist, your idle pose can ONLY be named $Harold(f6)(f2)_idle, and so is forced to be a 6 frame pose going at 2x speed
These three functions, combined, remove that limit. Now you can put $Harold(f6)(f2)_idle(f4)(s1) into your folder, and harold will settle down to 1x speed when doing a 4-frame idle pose.
How does it work?
First, the initialize tweak means that we create a full list of character names when the game first starts up.
The setPose tweak uses that character name list. It will still default to whatever exact pose you select, but if it doesn't find that EXACT pose, it will check to see if there's a character image which is that pose followed by some suffixes.
Finally, the setCharacterFrames tweaks the parsing on the filename tags, so it always picks the LAST one instead of the first one. So the pose's tags will override the main image name. As a bonus, it will also parse negative direction shifts as well as positive.
Code:var _crossengine_game_sys_init = Game_System.prototype.initialize
Game_System.prototype.initialize = function() {
_crossengine_game_sys_init.call(this);
this.crossEngine={};
this.rebuildFileList();
};
Game_System.prototype.rebuildFileList = function () {
//create a list of image files in our character directory.
// This is necessary for the automatic pose recognition
// so for example you can have $Character(f6).png and $Character(f6)_idle(f3).png
// and the default pose code to apply _idle will detect the right character name
//
var fs = require ("fs");
var path = require('path');
var base = path.dirname(process.mainModule.filename);
//let dir = fs.readdirSync( './img/characters/' );
let dir = fs.readdirSync( path.join(base, '/img/characters/'));
this.crossEngine.characterNameList = dir.filter( elm => elm.match(new RegExp(`.*\.(png)`, 'ig')));
this.crossEngine.characterNameListLC=['hello world'];//this should never appear in game.
//slice off the .png extension
for (var index =0; index<this.crossEngine.characterNameList.length;index++)
{
this.crossEngine.characterNameList[index]=this.crossEngine.characterNameList[index].slice(0, -4);
//create a lower case version of it so that we can do case matching for poses
this.crossEngine.characterNameListLC[index]=this.crossEngine.characterNameList[index].toLowerCase();
}
}
//rebuild our file list whenever we load a save game (to make testing easier)
var _cross_onLoadSuccess = Scene_Load.prototype.onLoadSuccess;
Scene_Load.prototype.onLoadSuccess=function(){
_cross_onLoadSuccess.call(this)
$gameSystem.rebuildFileList();
}
//==============================
// * From Mog_CharPoses.js
//==============================
// I have altered this with a fallback that CHECKS to see if a pose exists.
//if it DOES exist, then we proceed as normal.
//if it does NOT exist, then we first check to see if there's a pose with different
//parameters (like _idle(f3) instead of just _idle
//if that exists, then we use that one instead
//if it does not exist, we don't load anything
//and whine in the console about it
//BASICALLY:
// set your frames and speed and y offset and all that jazz
// at the end of your original image name
// AND at the end of any poses
// and everything will be fine and dandy
// if you have multiple versions of a pose file I think it PROBABLY just picks
// whichever is alphabetically first if you don't specify the exact file name
// but honestly that's a weird edge case and if you REALLY want to get that effect
// you're better off manipulating the framerate or y offset or whatever dynamically
// instead of having seperate files
// ALSO: since this scans once when the game initializes
// if your image files change midgame the list will get stale
// but like
// don't do that, alright? That's weird, and if you have something that complex
// you should just code your own system.
Game_CharacterBase.prototype.setPose = function() {
this._poses.idle[3] = false;
//default to keeping the same pose
var newPose=this._originalName.name;
if (this.isFaintPose()) {
newPose = this.setFaintPose();
} else if (this.isKnockbackPose()) {
newPose = this.setKnockbackPose();
} else if (this.isGuardPose()) {
newPose = this.setGuardingPose();
} else if (this.isActionPose()) {
newPose = this.setActionPose();
} else if (this.isVictoryPose()) {
newPose = this.setVictoryPose();
} else if (this.isCastingPose()) {
newPose = this.setCastingPose();
} else if (this.isAttackingPose()) {
newPose = this.setAttackingPose();
} else if (this.isPickUPPose()) {
newPose = this.setPickUPPose();
} else if (this.isPushPullPose()) {
newPose = this.setPushPullPose();
} else if (this.isDashingPose()) {
newPose = this.setDashPose();
} else if (this.isJumpingPose()) {
newPose = this.setJumpPose();
} else if (this.isIdlePose()) {
newPose = this.setIdlePose();
};
// this code didn't do anything in stock chrono engine. Mog was probably
// planning to expand this. Commented out for now
/* if (this.isDiagonalDefaultPose()) {
newPose = this.setDiagonalDefaultPose();
} else {
newPose = this._originalName.name;
}; */
//if the pose exists, return with it. Otherwise we will have to see if the
//parameters are different
var fs = require ("fs");
if ( fs.existsSync("./img/characters/" + newPose+'.png'))
{
//console.log(newPose)
return newPose
}else{
for (var index =0; index<$gameSystem.crossEngine.characterNameList.length;index++)
{
if ($gameSystem.crossEngine.characterNameList[index].startsWith (newPose))
{
return $gameSystem.crossEngine.characterNameList[index];
}
}
console.log('Could not find '+newPose+', using base image.')
return this._originalName.name
}
};
//From MOG_CharPoses
//==============================
// * Set Character Frames
//==============================
// I have edited this so you can have both negative offsets for x and y
// AND it now checks the LAST offset, not the first one.
// this means that if you have a pose with a different number of frames
// than the default, it'll pick up on that!
// for example, if the base character is Bob(f3), you can now have
// Bob(f3)_punch(f12)
Game_Character.prototype.setCharacterFrames = function() {
this.clearCharacterFrames();
var frames = this._characterName.match(/(\(F(\d+\.*\d*))/gi)
if (frames) {
this._frames.enabled = true;
this._frames.index = 0;
this._frames.max = Number(frames[frames.length-1].match(/\d+/i));
}
//edited to include support for negative offsets
var ex = this._characterName.match(/(X(-?\d+\.*\d*))/gi)
if (ex) {this._frames.x = Number(ex[ex.length-1].match(/-?\d+/i))};
var ey = this._characterName.match(/(Y(-?\d+\.*\d*))/gi)
if (ey) {this._frames.y = Number(ey[ey.length-1].match(/-?\d+/i))};
var sp = this._characterName.match(/(S(\d+\.*\d*))/gi)
if (sp) {this._frames.speed = Number(sp[sp.length-1].match(/\d+/i))};
if (this._frames.enabled) {this._pattern = 0};
this._pattern = this._frames.enabled ? 0 : 1;
};
Do I need to use CrossEngine plugin to utilize the Unlocking of Character Poses?
I tried adding all of this above code to a JS and import it but did nothing. How exactly do I go about implementing these 3 steps??
Do I create a new .JS for the First part of code? ie....
var _crossengine_game_sys_init = Game_System.prototype.initialize
Game_System.prototype.initialize = function() {
_crossengine_game_sys_init.call(this);
this.crossEngine={};
this.rebuildFileList();
};
Game_System.prototype.rebuildFileList = function () {
//create a list of image files in our character directory.
// This is necessary for the automatic pose recognition
// so for example you can have $Character(f6).png and $Character(f6)_idle(f3).png
// and the default pose code to apply _idle will detect the right character name
//
var fs = require ("fs");
var path = require('path');
var base = path.dirname(process.mainModule.filename);
//let dir = fs.readdirSync( './img/characters/' );
let dir = fs.readdirSync( path.join(base, '/img/characters/'));
this.crossEngine.characterNameList = dir.filter( elm => elm.match(new RegExp(`.*\.(png)`, 'ig')));
this.crossEngine.characterNameListLC=['hello world'];//this should never appear in game.
//slice off the .png extension
for (var index =0; index<this.crossEngine.characterNameList.length;index++)
{
this.crossEngine.characterNameList[index]=this.crossEngine.characterNameList[index].slice(0, -4);
//create a lower case version of it so that we can do case matching for poses
this.crossEngine.characterNameListLC[index]=this.crossEngine.characterNameList[index].toLowerCase();
}
}
//rebuild our file list whenever we load a save game (to make testing easier)
var _cross_onLoadSuccess = Scene_Load.prototype.onLoadSuccess;
Scene_Load.prototype.onLoadSuccess=function(){
_cross_onLoadSuccess.call(this)
$gameSystem.rebuildFileList();
}
And then Do I edit the .js MOG.CharaPoses for the second and third part of this process?
I cant figure out how to get this working so I can use different names Example... $Hero01(F8)(S1)_act01(F5)(S3)