RMMV Need Stats Shown (Skill Tree)

Frostorm

[]D[][]V[][]D aka "Staf00"
Veteran
Joined
Feb 22, 2016
Messages
1,531
Reaction score
1,115
First Language
English
Primarily Uses
RMMV
So I'm currently using @SomeFire's SkillTreeSystem plugin and created a Stat Allocation "skill tree". The way I designed it turned out to leave quite a bit of empty space, perfect for the actor's current base params to be shown.

Screenshot
1603951503323.png

Basically, I want to show the actor's main stats (e.g. ATK) in the bottom left area. I decided not to bug @SomeFire in his plugin thread since this request would be outside the original scope of his plugin.

I thought about creating a new window, but I would only want it to show if the "Allocation" tree is selected since all other trees take up the full space of the left window. A better solution would be to draw the base params/stats directly in the existing window. I just don't know how to go about this since the formatting in this plugin is a bit unique. All I know is that I definitely need an "if Allocation tree is selected" conditional statement.

This is the code for the bottom left window:
JavaScript:
//-----------------------------------------------------------------------------
// Skills Window
//
// The window for selecting a skill on the abilities screen.

function Skills_Window() {
  this.initialize.apply(this, arguments);
}

Skills_Window._lastSelectedIndex = {};

Skills_Window.prototype = Object.create(Window_Selectable.prototype);
Skills_Window.prototype.constructor = Skills_Window;

Skills_Window.prototype.initialize = function(x, y) {
    Window_Selectable.prototype.initialize.call(this, x, y, this.windowWidth(), this.windowHeight());
    this._actor = null;
    this._tree = null;
    this._descriptionWindow = null;
};

Skills_Window.prototype.setDescriptionWindow = function(descriptionWindow) {
    this._descriptionWindow = descriptionWindow;
};

Skills_Window.prototype.maxItems = function() {
    return this._tree ? this._tree.skills.length : 0;
};

Skills_Window.prototype.maxCols = function() {
    return SkillTreesSystem.skillWindowMaxCols;
};

Skills_Window.prototype.windowWidth = function() {
    return this.itemWidth() * SkillTreesSystem.skillWindowDrawCols + this.standardPadding() * 2;
};

Skills_Window.prototype.windowHeight = function() {
    return Graphics.boxHeight - this.fittingHeight(1);
};

Skills_Window.prototype.setActor = function(actor) {
    if (this._actor !== actor) {
        this._actor = actor;
        this._tree = null;
        this.selectLast();
        this.refresh();
    }
};

Skills_Window.prototype.setSkillTree = function(symbol) {
    this._tree = this.findTree(symbol);
    this.refresh();
};

Skills_Window.prototype.findTree = function(symbol) {
    if (!symbol)
        return null;

    if (this._actor && this._actor.skillTrees) {
        var trees = this._actor.skillTrees.trees;

        for (var i = 0; i < trees.length; i++) {
            if (trees[i].symbol === symbol)
                return trees[i];
        }
    }

    return null;
};

Skills_Window.prototype.itemWidth = function() {
    return Window_Base._iconWidth * SkillTreesSystem.skillScale;
};

Skills_Window.prototype.itemHeight = function() {
    return Window_Base._iconHeight * SkillTreesSystem.skillScale;
};

Skills_Window.prototype.drawItem = function(treeObj, index) {
    var x = this.itemWidth() * (index % SkillTreesSystem.skillWindowMaxCols) - this._scrollX;
    var y = this.itemHeight() * Math.floor(index / SkillTreesSystem.skillWindowMaxCols) - this._scrollY + 16;

    this.changePaintOpacity(treeObj.isEnabled(this._actor, this._tree));
    this.drawIcon(treeObj.iconId(), x, y);
    this.changePaintOpacity(1);

    if (treeObj instanceof Skill) {
        var size = this.contents.fontSize;
        this.contents.fontSize = this.itemHeight() / 3;

        if (treeObj.currentLevel() === treeObj.maxLevel())
            var text = "MAX";
        else
            text = treeObj.currentLevel() + "/" + treeObj.maxLevel();

        this.drawText(text, x + 2, y + this.itemHeight() / 4, this.itemWidth() - 4, 'center');

        this.contents.fontSize = size;
    }
};

Skills_Window.prototype.drawText = function(text, x, y, maxWidth, align) {
    this.contents.drawText(text, x, y, maxWidth, this.lineHeight() * SkillTreesSystem.skillScale, align);
};

Skills_Window.prototype.drawIcon = function(iconIndex, x, y) {
    var bitmap = ImageManager.loadSystem('IconSet');
    var pw = Window_Base._iconWidth;
    var ph = Window_Base._iconHeight;
    var sx = iconIndex % 16 * pw;
    var sy = Math.floor(iconIndex / 16) * ph;
    this.contents.blt(bitmap, sx, sy, pw, ph, x, y, pw * SkillTreesSystem.skillScale, ph * SkillTreesSystem.skillScale);
};

Skills_Window.prototype.drawAllItems = function() {
    if (!this._tree)
        return;

    this._tree.skills.forEach(function(item, idx) {
        if (item instanceof TreeObject)
            this.drawItem(item, idx);
    }, this);
};

Skills_Window.prototype.refresh = function() {
    if (this.contents) {
        this.contents.clear();
        this.drawAllItems();
    }
};

Skills_Window.prototype.select = function(index) {
    if (index !== -1 && (this._tree && !(this._tree.skills[index] instanceof Skill)))
        return;

    Window_Selectable.prototype.select.call(this, index);

    if (index === -1)
        return;

    if (this._descriptionWindow) {
        let skill = this._tree ? this._tree.skills[index] : null;

        this._descriptionWindow.showDescription(this._tree, skill);

        if (!SkillTreesSystem.learnByDoubleClick && skill instanceof Skill) {
            this._confirmationButton.skill = skill;
            this._confirmationButton.actor = this._actor;
            this._confirmationButton.tree = this._tree;

            if (skill.isAvailableToLearn(this._actor, this._tree))
                this._confirmationButton.show();
            else
                this._confirmationButton.hide();
        }
    }
};

Skills_Window.prototype.selectLast = function() {
    if (!this._actor || !this._tree) {
        this.deselect();

        return;
    }

    if (!Skills_Window._lastSelectedIndex[this._actor.actorId()])
        Skills_Window._lastSelectedIndex[this._actor.actorId()] = {};

    if (!Skills_Window._lastSelectedIndex[this._actor.actorId()][this._tree.symbol]) {
        for (let i = 0; i < this._tree.skills.length; i++) {
            if (this._tree.skills[i] instanceof Skill) {
                Skills_Window._lastSelectedIndex[this._actor.actorId()][this._tree.symbol] = i;
                break;
            }
        }
    }

    this.select(Skills_Window._lastSelectedIndex[this._actor.actorId()][this._tree.symbol]);
};

Skills_Window.prototype.itemRect = function(index) {
    var rect = new Rectangle();
    var maxCols = this.maxCols();
    rect.width = this.itemWidth() + 4;
    rect.height = this.itemHeight() + 4;
    rect.x = this.itemWidth() * (index % maxCols) - this._scrollX - 2;
    rect.y = this.itemHeight() * Math.floor(index / maxCols) - this._scrollY + 14;
    return rect;
};

Skills_Window.prototype.updateCursor = function() {
    if (this.isCursorVisible()) {
        var rect = this.itemRect(this.index());

        if (SkillTreesSystem.skillCursorMargin) {
            this.setCursorRect(rect.x + this.spacing() / 2, rect.y + this.spacing() / 2,
                rect.width + this.spacing(), rect.height + this.spacing());
        } else
            this.setCursorRect(rect.x + this.spacing(), rect.y + this.spacing(), rect.width, rect.height);
    } else
        this.setCursorRect(0, 0, 0, 0);

    /*
    if (this._cursorAll) {
        var allRowsHeight = this.maxRows() * this.itemHeight();
        this.setCursorRect(0, 0, this.contents.width, allRowsHeight);
        this.setTopRow(0);
    } else if (this.isCursorVisible()) {
        var rect = this.itemRect(this.index());
        this.setCursorRect(rect.x, rect.y, rect.width, rect.height);
    } else {
        this.setCursorRect(0, 0, 0, 0);
    }
    */
};

Skills_Window.prototype.cursorDown = function(wrap) {
    var index = this.index();
    var maxItems = this.maxItems();
    var maxCols = SkillTreesSystem.skillWindowMaxCols;
    var index0 = this.index() % maxCols;
    var skills = this._tree.skills;

    while (index < maxItems) {
        index = index + maxCols;

        if (index >= maxItems && index0 < maxCols)
            index = ++index0;

        if (index < maxItems && skills[index] instanceof Skill)
            break;
    }

    if (skills[index])
        this.select(index);
};

Skills_Window.prototype.cursorUp = function(wrap) {
    var index = this.index();
    var maxItems = this.maxItems();
    var maxCols = SkillTreesSystem.skillWindowMaxCols;
    var index0bound = Math.floor(maxItems / maxCols) * maxCols;
    var index0 = this.index() % maxCols + index0bound;
    var skills = this._tree.skills;

    while (index >= 0) {
        index = index - maxCols;

        if (index < 0 && index0 - 1 > index0bound)
            index = --index0;

        if (index >= 0 && skills[index] instanceof Skill)
            break;
    }

    if (skills[index])
        this.select(index);
};

Skills_Window.prototype.cursorRight = function(wrap) {
    var index = this.index();
    var maxItems = this.maxItems();
    var maxCols = SkillTreesSystem.skillWindowDrawCols;
    var skills = this._tree.skills;

    if (maxCols >= 2 && (index < maxItems - 1 || (wrap && this.isHorizontal()))) {
        while (++index < maxItems && !(skills[index] instanceof Skill));

        if (skills[index])
            this.select((index) % maxItems);
    }
};

Skills_Window.prototype.cursorLeft = function(wrap) {
    var index = this.index();
    var maxItems = this.maxItems();
    var maxCols = SkillTreesSystem.skillWindowDrawCols;
    var skills = this._tree.skills;

    if (maxCols >= 2 && (index > 0 || (wrap && this.isHorizontal()))) {
        while (--index > 0 && !(skills[index] instanceof Skill));

        if (skills[index])
            this.select((index + maxItems) % maxItems);
    }
};

/**
* @method _refreshCursor
* @private
*/
Skills_Window.prototype._refreshCursor = function() {
    this._padding -= this.spacing();
    Window.prototype._refreshCursor.call(this);
    this._padding += this.spacing();
};

Skills_Window.prototype.isCursorVisible = function() {
    var row = this.row();

    return row >= this.topRow() && row <= this.bottomRow();
};

SkillTreesSystem.ensureCursorVisible = Window_Selectable.prototype.ensureCursorVisible;
Skills_Window.prototype.ensureCursorVisible = function() {
    SkillTreesSystem.ensureCursorVisible.call(this);

    var col = this.column();
    if (col < this.rightColumn()) {
        this.setRightColumn(col);
    } else if (col > this.leftColumn()) {
        this.setLeftColumn(col);
    }

    /*
    var row = this.row();
    if (row < this.topRow()) {
        this.setTopRow(row);
    } else if (row > this.bottomRow()) {
        this.setBottomRow(row);
    }
     */
};

Skills_Window.prototype.column = function() {
    return this.index() % SkillTreesSystem.skillWindowMaxCols;
};

Skills_Window.prototype.rightColumn = function() {
    return Math.floor(this._scrollX / this.itemWidth());
};

Skills_Window.prototype.maxRightColumn = function() {
    return Math.max(0, this.maxCols() - SkillTreesSystem.skillWindowDrawCols);
};

Skills_Window.prototype.setRightColumn = function(col) {
    var scrollX = col.clamp(0, this.maxRightColumn()) * this.itemWidth();
    if (this._scrollX !== scrollX) {
        this._scrollX = scrollX;
        this.refresh();
        this.updateCursor();
    }
};

Skills_Window.prototype.leftColumn = function() {
    return Math.max(0, this.rightColumn() + SkillTreesSystem.skillWindowDrawCols - 1);
};

Skills_Window.prototype.setLeftColumn = function(row) {
    this.setRightColumn(row - (SkillTreesSystem.skillWindowDrawCols - 1));
};

Skills_Window.prototype.isCurrentItemEnabled = function() {
    let actor = this._descriptionWindow._actor;
    let tree = this._descriptionWindow._tree;
    let skill = this._descriptionWindow._skill;

    return skill.isAvailableToLearn(actor, tree);
};

SkillTreesSystem.skillsWindow_processOk = Skills_Window.prototype.processOk;
Skills_Window.prototype.processOk = function() {
    if (SkillTreesSystem.learnByDoubleClick)
        SkillTreesSystem.skillsWindow_processOk.call(this);
};
 
Last edited:

ramza

Lunatic Coder
Veteran
Joined
Jan 28, 2013
Messages
773
Reaction score
483
First Language
English
Primarily Uses
RMMV
Messing around in other peoples menu systems is one of my things I'm pretty good at. I think I should be able to get this to do what you want. I haven't started working on it just yet, but I figured I'd post early just in case someone else decides to start working on it between now and when I finish it.
 

Frostorm

[]D[][]V[][]D aka "Staf00"
Veteran
Joined
Feb 22, 2016
Messages
1,531
Reaction score
1,115
First Language
English
Primarily Uses
RMMV
Messing around in other peoples menu systems is one of my things I'm pretty good at. I think I should be able to get this to do what you want. I haven't started working on it just yet, but I figured I'd post early just in case someone else decides to start working on it between now and when I finish it.
Thank you! Btw, I'm going to purchase your Halloween bundle today. So glad you mentioned the deal. ^.^
 

ramza

Lunatic Coder
Veteran
Joined
Jan 28, 2013
Messages
773
Reaction score
483
First Language
English
Primarily Uses
RMMV
Alright, I think it's in a workable enough state to share, and see if there're any weird glitches with it for your specific use case.

I tested it in SomeFires demo project, and it seems to work fine there, but I didn't want to put in the extra effort to modify his demo skill trees too much to make sure it does what I think it should.

skilltree.png

Basically, if you're currently selecting a tree whose symbol is specified in this plugin, the actor status info is drawn in the bottom left, as requested. I tried to make it dynamically scale the text size so that it always had enough room to draw all 8 params, regardless of resolution, the idea being that it should scale to larger windows automatically. It seems like all of the default trees in the demo are the same length, though, except for the big_tree, and I'm not entirely sure how that one works because it doesn't seem like I could get it to draw anything for that one. Which should be fine anyway, since you only wanted it for a smaller tree.

Since I tied it to the function that draws the items for the window already, it should update whenever that window refreshes without issue, though since I didn't make any skills that actually increased parameters, I didn't actually test this the right way. Manually calling SceneManager._scene._skillsWindow.refresh() after changing the actors paramPlus value for Hp did correctly show his hp change, though, so I'm confident this works.

Terms of Use:
  • Free for commercial and non-commercial use, with credit to me, Ramza.
  • Do not edit the header of this plugin, or claim sole ownership of it.
  • Editing the plugin to add new features, or fix compatibility problems is allowed.
  • Redistributing this plugin is also allowed.
Given a bit more time, I could probably make it mimic how the yanfly plugins look, with the dark box outlines and such, but that's a task for another time, if needed.
 

Attachments

Frostorm

[]D[][]V[][]D aka "Staf00"
Veteran
Joined
Feb 22, 2016
Messages
1,531
Reaction score
1,115
First Language
English
Primarily Uses
RMMV
@ramza Omg, ur the best!! I can't express how helpful this is. It's pretty much perfect, the only thing I'm gonna edit is disabling the HP & MP stats shown since I have the gauges set up already. Still, it was a good call including it since others might want those shown.

1603993417088.png

As you can see, the stats block is cut off on the bottom in my current setup (I may reduce the top window back down to 1 or 2 lines tho). Sorry for being picky, but could you guide me to where/what I need to edit to hide Max HP & Max MP?
JavaScript:
 Skills_Window.prototype.drawActorParams = function(index){
    var textY =  this.itemHeight() * Math.floor((index) / SkillTreesSystem.skillWindowMaxCols)
    if (this._actor){
        var fontSize = Math.round((this.contents.height - textY - (this.standardPadding())) / 9)
        this.contents.fontSize = fontSize
        for (let i = 0; i < 8; i++){
            textY += fontSize + 2
            var paramName = TextManager.param(i)
            var paramValue = this._actor.param(i)
            var paramNameWidth = this.getLargestParamNameLength()
            this.changeTextColor(this.systemColor())
            this.drawText(paramName, 2, textY, paramNameWidth)
            this.resetTextColor()
            this.drawText(paramValue, 6 + paramNameWidth, textY, this.contents.width - paramNameWidth - (this.standardPadding()/2), "right")
        }
        this.resetFontSettings()
    }
};
My 1st guess was to change "let i = 0" to "let i = 2" but that didn't change anything for some reason. Any tips? Thx.

Edit: I even tried this mess of a code but still resulted in ZERO changes from the original...
JavaScript:
Skills_Window.prototype.drawActorParams = function(index){
    var textY =  this.itemHeight() * Math.floor((index) / SkillTreesSystem.skillWindowMaxCols)
    if (this._actor){
        var fontSize = Math.round((this.contents.height - textY - (this.standardPadding())) / 9)
        this.contents.fontSize = fontSize
        var paramNameWidth = this.getLargestParamNameLength()
        this.changeTextColor(this.systemColor())
        this.drawText(TextManager.param(2), 2, textY, paramNameWidth)
        this.resetTextColor()
        this.drawText(this._actor.param(2), 6 + paramNameWidth, textY, this.contents.width - paramNameWidth - (this.standardPadding()/2), "right")
        this.changeTextColor(this.systemColor())
        this.drawText(TextManager.param(3), 2, textY + 30, paramNameWidth)
        this.resetTextColor()
        this.drawText(this._actor.param(3), 6 + paramNameWidth, textY + 30, this.contents.width - paramNameWidth - (this.standardPadding()/2), "right")
        this.changeTextColor(this.systemColor())
        this.drawText(TextManager.param(4), 2, textY + 60, paramNameWidth)
        this.resetTextColor()
        this.drawText(this._actor.param(4), 6 + paramNameWidth, textY + 60, this.contents.width - paramNameWidth - (this.standardPadding()/2), "right")
        this.changeTextColor(this.systemColor())
        this.drawText(TextManager.param(5), 2, textY + 90, paramNameWidth)
        this.resetTextColor()
        this.drawText(this._actor.param(5), 6 + paramNameWidth, textY + 90, this.contents.width - paramNameWidth - (this.standardPadding()/2), "right")
        this.changeTextColor(this.systemColor())
        this.drawText(TextManager.param(6), 2, textY + 120, paramNameWidth)
        this.resetTextColor()
        this.drawText(this._actor.param(6), 6 + paramNameWidth, textY + 120, this.contents.width - paramNameWidth - (this.standardPadding()/2), "right")
        this.changeTextColor(this.systemColor())
        this.drawText(TextManager.param(7), 2, textY + 150, paramNameWidth)
        this.resetTextColor()
        this.drawText(this._actor.param(7), 6 + paramNameWidth, textY + 150, this.contents.width - paramNameWidth - (this.standardPadding()/2), "right")
/*        for (let i = 2; i < 8; i++){
            textY += fontSize + 2
            var paramName = TextManager.param(i)
            var paramValue = this._actor.param(i)
            var paramNameWidth = this.getLargestParamNameLength()
            this.changeTextColor(this.systemColor())
            this.drawText(paramName, 2, textY, paramNameWidth)
            this.resetTextColor()
            this.drawText(paramValue, 6 + paramNameWidth, textY, this.contents.width - paramNameWidth - (this.standardPadding()/2), "right")
        }*/
        this.resetFontSettings()
    }
};
Edit2: Omfg, I'm an idiot...I've been editing the JS file from my DL folder and not the copy of the plugin I pasted in the plugins folder. Lol, no wonder my edits weren't having any effect... -.-
Fixed!! I can also confirm that the stats do refresh upon learning a skill. So this stat allocation skill tree feature works flawlessly! :kaopride:
1603998158975.png
 
Last edited:

ShadowDragon

Veteran
Veteran
Joined
Oct 8, 2018
Messages
2,861
Reaction score
1,004
First Language
Dutch
Primarily Uses
RMMV
I dont use it, but I gotta say, I love this version than the original one :)
nice going though =)
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Evil7 added!


I did a bit of a remake on one of the maps, also I made a particle for jumping into the portal, and one for traveling through the portal. I'll probably add more sparkles later to embellish it. :LZSwink:
Polished the animation and added details :kaojoy:
Ami
What do you think about the Wood Bridge inside of Volcano?
Yet another gaming question, i'm currently playing Last of Us 2 and want to get another game to play next but can't decide between Ghost of Tsushima, Miles Morales & Jedi Fallen Order. After the latest mandalorian i AM on a star wars kick, but i also LOVED the last spiderman game that prequels Miles Morales. Ghost of Tsushima is the bottom of my list but i heard it was AWESOME. Just want a good story & fun gameplay.

Forum statistics

Threads
105,686
Messages
1,015,535
Members
137,362
Latest member
sdramose
Top