Uranium

Game Dev, Pixel Artist
Veteran
Joined
Jan 13, 2017
Messages
164
Reaction score
61
First Language
English
Primarily Uses
RMMV
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;
};
Edit: I got it working! Thanks Restart! :D Question: Do you think I could add more poses to the list easily?
 

TheGentlemanLoser

"And when we fall, we will fall together..."
Veteran
Joined
Dec 30, 2020
Messages
310
Reaction score
361
First Language
English
Primarily Uses
RMMV
Hi, I'm posting this question to this thread specifically because I think in spite of just being "Restart's notes to self" it's actually the biggest single general repository of useful info/speculation/tweaking to the Crono Engine on this site (speaking of 'notes to self' I have four projects that technically aren't cancelled, two of them including my present hardcore crunch spooky season project use the Chrono engine, and two don't).

So anyway, right now I think I have discovered that if you create a new tool event on the tool map, when you load a save game, the weapon/tool/presumably skill (have only tested 'weapon') associated with that tool event won't function AT ALL, and you actually need to start a new game to see that tool work (like, it kind of "initializes" it from the tool map at game start?). I am looking primarily for confirmation on this and I'm curious if anyone has figured out a workaround. If not, I'm going to need to adjust my workflow dramatically to get all of my weapons/tools set up correctly in the editor before continuing to lay down events/story in a linear fashion.
 

ATT_Turan

Forewarner of the Black Wind
Veteran
Joined
Jul 2, 2014
Messages
2,231
Reaction score
1,194
First Language
English
Primarily Uses
RMMV
So anyway, right now I think I have discovered that if you create a new tool event on the tool map, when you load a save game, the weapon/tool/presumably skill (have only tested 'weapon') associated with that tool event won't function AT ALL, and you actually need to start a new game to see that tool work (like, it kind of "initializes" it from the tool map at game start?). I am looking primarily for confirmation on this and I'm curious if anyone has figured out a workaround.
That's how RPG Maker functions. The state of maps is saved in the save game, so any alterations require you to leave and reload the map. Since it sounds like this is not a map your character can actually go to, you won't have a way to do that.

This is also true, but more so, with anything specified in the database. Additions that you make will show up when loading a save game, but changes will not. Changing anything to do with plugins also won't load from a save. So there's a lot of stuff that can only be tested by starting a new game.
 

Latest Threads

Latest Posts

Latest Profile Posts

you know, some days you get resentful that game dev is even considered a "fun job" and other days it's like, welp, time to roll up my sleeves and code these molotov cocktails
If you suck at playing trumpets, that is probably why.
Been sick with a stomach virus for seven days now. Not going to work tomorrow because I'm still contagious according to my doctor.
Much as I love my job, I really hate playing "office politics". It would be nice if I didn't have to pretend to be someone else all day long.
I wanna get back into showing off Battlers and other assets I create again. But i'm always haunted by the "It's not good/realistic enough" voices that keep me from doing so.

Maybe I should get back to it, I did enjoy showing off whatever I came up with!

Forum statistics

Threads
115,958
Messages
1,094,380
Members
151,220
Latest member
Dolton
Top