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
339
Reaction score
451
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,830
Reaction score
1,651
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.
 

TheGentlemanLoser

"And when we fall, we will fall together..."
Veteran
Joined
Dec 30, 2020
Messages
339
Reaction score
451
First Language
English
Primarily Uses
RMMV
Thanks @ATT_Turan.

Fellow Chrono Engine users, have any of you found a gamepad/controller plugin that works with Moghunter's stuff? I haven't seen one where I can actually map 'D', 'A', 'Q', and 'E' to face buttons, or at least, I can't figure out how to do that with the YEP Gamepad Config plugin, and the other popular Gamepad plugin I've seen seems to need to remap keyboard controls to W,A,S,D for movement instead of arrow keys which is not desirable for me for this project.

Has anyone ever implemented clips/reloading for weapons into Chrono Engine? Probably a long shot, I know.
 

Latest Threads

Latest Profile Posts

Evening humans! How goes the game make?
The anime characters we saw 20 years ago,
still have the same age when we see them now.
Somehow it's strange but also beautiful.
It's like no matter how much we change,
there's certain part of ourselves we can reconnect to when we see them again.
Took a long, long time, way longer than it should to be honest...but I've finally finished the big content update to my demo!
Lots of not good things happening IRL but I'm not gonna let this day end like this. Quote time:
"Success is not final, failure is not fatal: it is the courage to continue that counts." -Winston Churchill

So, keep going, lads. Whatever you do keep going. Until next time.

It's a Spanish devlog don't get scared!. (please)

Forum statistics

Threads
117,239
Messages
1,105,797
Members
153,404
Latest member
Control_Studios
Top