Sorting Menu Contents By Category (SOLVED)

Camkitsune

Veteran
Veteran
Joined
Mar 9, 2017
Messages
34
Reaction score
4
First Language
English
Primarily Uses
RMMV
So, I've got a category window that's supposed to filter the items in the primary list based on their associated category. I've based my code off of what the game uses for the ItemCategory window.

Unfortunately, it doesn't do anything. I haven't been able to pinpoint the problem, either - there may actually be several.

Code:
/*----------------------------------------------------------------------------*
 *        PLUGIN SETUP                                                          *
 *----------------------------------------------------------------------------*/
//Get the plugin parameters.
var intelParameters = PluginManager.parameters('IntelSystem');

 //Get the intel data from the json file.
DataManager.loadDataFile('$dataIntel', intelParameters.JsonFileName);
 
//Define getter for the IntelData.
DataManager.getIntelData = function(id) {
    for (var x = 0; x < $dataIntel.length; x++) {
        if ($dataIntel[x].id == Number(id)) {
            return $dataIntel[x];
        }
    }
    return null;
};

DataManager.getNewIntel = function(args) {
    var intelData = DataManager.getIntelData(args[1]);
   
    var contents = [];
    if (args.length < 3 || args[2] == "all") {
        contents = intelData.contents;
    } else {
        for (var x = 0; x < intelData.contents.length; x++) {
            contents.push(null);
        }
        for (var y = 2; y < args.length; y++) {
            var target = Number(args[y]);
            if (target < contents.length) {
                contents[target] = intelData.contents[target];
            }
        }
    }
    return new IntelItem(intelData.id, intelData.topic, intelData.category, contents, intelData.pic);
};

//Add the plugin commands.
Game_Interpreter.prototype.pluginCommand = (function (original) {
    "use strict";

    // Define the function that will replace the original.

    function pluginCommand(command, args) {
        original.call(this, command, args);
        if (command !== "Intel") {
            return;
        }
        var newIntel = DataManager.getNewIntel(args);
        switch (args[0]) {
            case "add":
                //intelData is also passed in to reduce calls to the DataManager.
                var result = $gameParty.IntelList.addIntel(newIntel);
                //TODO: create popup window.
                break;
            case "check":
                return $gameParty.IntelList.hasIntel(newIntel);
            case "showAlerts":
                intelParameters.ShowAlerts = (args[1]);
                break;
            case "debug":
                var debugIntel = DataManager.getNewIntel([null, 1, "all"]);
                $gameParty.IntelList.addIntel(debugIntel);
                $gameParty.IntelList.addIntel(DataManager.getNewIntel([null, 2, "all"]));
                $gameParty.IntelList.addIntel(DataManager.getNewIntel([null, 3, "all"]));
                break;
            default:
                break;
        }
    }

    return pluginCommand;
}(Game_Interpreter.prototype.pluginCommand));

//Add initialization of IntelList to $gameParty
Game_Party.prototype.initialize =  (function (original) {
    "use strict";
    function initialize() {
        original.call(this);
        this.IntelList = new IntelList();
    }
    return initialize;
}(Game_Party.prototype.initialize));

/*----------------------------------------------------------------------------*
 *        CORE FUNCTIONS                                                          *
 *----------------------------------------------------------------------------*/

//Object constructor for IntelItem.
function IntelItem(idnum, topic, category, contents, pic) {
    //ID is used to simplify the lookup process.
    this.id = idnum;
    //Topics are what the specific informatoin will appear on: IE, the subject of the intel.
    this.topic = topic;
    //Categories are used for in-game filtering.
    this.category = category;
    //Array representing specific lines of information.
    this.contents = contents;
    //Used for the picture, if an item has one.
    this.pic = pic;
}
 
 //Function is used as part of evaluation of whether a new intel item's contents are already in the player's Intel inventory.
IntelItem.prototype.matches = function (intelFromList) {
    var index = 0;
    //isMatch first checks if the topics match; while loop won't even start if they don't.
    var isMatch = (this.id === intelFromList.id);    
    while (isMatch && index <  this.contents.length) {
        //Return true if the contents are null (meaning they weren't to be checked), OR if they do and they match.
        isMatch = (!this.contents[index] || this.contents[index] == intelFromList.contents[index]);
        index++;
    }
    return isMatch;
};

//Function adds contents FROM the calling function TO the item given as an argument; the intent is that the item passed as an argument accesses the info from IntelList.
IntelItem.prototype.addNewContents = function(intelFromList){
    var newContentsAdded = false;
    for (var index = 0; index < this.contents.length; index++) {
        if (this.contents[index] && !intelFromList.contents[index]) {
            newContentsAdded = true;
            intelFromList.contents[index] = this.contents[index];
        }
    }
    return newContentsAdded;
};

//Function returns the IntelItem.contents array as a single formated string, ready to be written into the menu.
IntelItem.prototype.getContents = function(){
    var result = "";
    for (var x = 0; x < this.contents.length; x++) {
        result += "  " + this.contents[x];
    }
    return result;
};
   
//IntelList handles in-game inventory of IntelItems, provides sorting functionality.
function IntelList() {
    this.IntelItems = [];
    this.IntelCategories = [];
}
 
//Function updates the intel listing with new items, new categories, and new contents for extant items.  Returns a string for use with alerts.  
IntelList.prototype.addIntel = function(targetIntel, intelData) {
    //Premature break if a null argument is added.
    if (!targetIntel) return;
   
    //Insert category if it isn't in the categories list.
    if (this.IntelCategories.indexOf(targetIntel.category) === -1) {
        this.IntelCategories.push(targetIntel.category);
        this.IntelCategories.sort();
    }
   
    var result = null;
    var dexVal = this.findIndex(targetIntel);
    if (dexVal === this.IntelItems.length) {
        this.IntelItems.push(targetIntel);
        result = "New intelligence file: " + targetIntel.topic;
    } else {
        var intelAtIndex = this.IntelItems[dexVal];
        if (intelAtIndex.id != targetIntel.id) {
            this.IntelItems.splice(dexVal, 0, targetIntel);
            result = "New intelligence file: " + targetIntel.topic;
        } else {
            var contentsCheck = targetIntel.addNewContents(intelAtIndex);
            if (contentsCheck){
                result = "Information updated: " + targetIntel.topic;
            }
        }
    }
    if (intelParameters.ShowAlerts) {
        return result;
    } else {
        return null;
    }
};
 
//Helper function for addIntel function; makes sure new intel is inserted alphabetically.
IntelList.prototype.findIndex = function (targetIntel) {
    var index = 0;
    var searching = true;
    while (index < this.IntelItems.length && searching) {
        var resultVal = targetIntel.topic.localeCompare(this.IntelItems[index].topic);
        if (resultVal <= 0) {
            searching = false;
        } else {
            index++;
        }
    }
    return index;
};

//Function determines whether or not the specified intel is present in the player's intel inventory.
IntelList.prototype.hasIntel = function(targetIntel) {
    //searchFunction must be defined this way due to how Array.some handles the function.
    var searchFunction = function(intelFromList){
        //The IntelItem.matches function checks to see if the intel item taken from the list has the same ID as well as all of the contents it has.
        return targetIntel.matches(intelFromList);
    };
    return this.IntelItems.some(searchFunction);
};

//Returns an array of IntelItems with the specified topic.
IntelList.prototype.getIntelFromCategory = function(categoryName){
    var result = [];
    for (var index = 0; index < this.IntelItems.length; index++) {
        if (this.IntelItems[index].category === categoryName) {
            result.push(this.IntelItems[index]);
        }
    }
    return result;
};
Code:
/*----------------------------------------------------------------------------*
 *        SCENE FUNCTIONS                                                          *
 *----------------------------------------------------------------------------*/
//Patch in the handler for the Intel command.
Scene_Menu.prototype.createCommandWindow = (function (original) {
    "use strict";
    function createCommandWindow() {
        original.call(this);

        this._commandWindow.setHandler("intel", function () {
            SceneManager.push(Scene_Intel);
        });
    }

    return createCommandWindow;
}(Scene_Menu.prototype.createCommandWindow));

//Patch the Intel command into the list of commands on the in-game menu.
Window_MenuCommand.prototype.addOriginalCommands = (function (original) {
    "use strict";
    function addOriginalCommands() {
        original.call(this);
        this.addCommand("Intel", "intel", ($gameParty.IntelList.IntelItems.length > 0));
    }

    return addOriginalCommands;
}(Window_MenuCommand.prototype.addOriginalCommands));

//Define initialization, prototype, and constructor.
function Scene_Intel() {this.initialize.apply(this, arguments);}
Scene_Intel.prototype = Object.create(Scene_MenuBase.prototype);
Scene_Intel.prototype.constructor = Scene_Intel;
Scene_Intel.prototype.initialize = function() {Scene_MenuBase.prototype.initialize.call(this);};

//Define creation and termination events.
Scene_Intel.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);
    this.createIntelCatsWindow();
    this.createIntelContentsWindow();
    this.createIntelTopicsWindow();
    this._topicWindow.activate();
};

Scene_Intel.prototype.terminate = function() {
    Scene_MenuBase.prototype.terminate.call(this);
};

//Creates the category list.
Scene_Intel.prototype.createIntelCatsWindow = function() {
    this._categoryWindow = new Window_IntelCategory(0,0);
    this._categoryWindow.makeCommandList();
    this.addWindow(this._categoryWindow);
};

//Creates the window in which the contents will appear.
Scene_Intel.prototype.createIntelContentsWindow = function() {
    this._contentsWindow = new Window_IntelContents(Math.floor(Graphics.boxWidth*0.25), this._categoryWindow.height, Math.ceil(Graphics.boxWidth * 0.75), Graphics.boxHeight - this._categoryWindow.windowHeight());
    this._categoryWindow.setHandler('ok', this.onCategoryOK.bind(this));
    this._categoryWindow.setHandler('cancel', this.popScene.bind(this));
    this.addWindow(this._contentsWindow);
};


//Creates the list of intel items.
Scene_Intel.prototype.createIntelTopicsWindow = function() {
    var catWindow = this._categoryWindow;
    this._topicWindow = new Window_IntelTopics(0, catWindow.height, Math.floor(Graphics.boxWidth * 0.25), Graphics.boxHeight - catWindow.windowHeight(), this._contentsWindow, catWindow);
    this._topicWindow.drawAllTopics();
    this.addWindow(this._topicWindow);
    catWindow.topicWindow = this._topicWindow;
   
};
Scene_Intel.prototype.onCategoryOK = function() {
    this._categoryWindow.update();
    this._categoryWindow.deselect();
    this._topicWindow.activate();
};
Code:
/*----------------------------------------------------------------------------*
* WINDOW FUNCTIONS *
/*----------------------------------------------------------------------------*/
//Window for the list of categories
function Window_IntelCategory() {this.initialize.apply(this, arguments);}
Window_IntelCategory.prototype = Object.create(Window_HorzCommand.prototype);
Window_IntelCategory.prototype.constructor = Window_IntelCategory;

Window_IntelCategory.prototype.initialize = function(x, y) {
    Window_HorzCommand.prototype.initialize.call(this, x, y);
    this.topicWindow = null;
};

Window_IntelCategory.prototype.windowWidth = function() {return Graphics.boxWidth;};
Window_IntelCategory.prototype.maxCols = function() {return 5;};
Window_IntelCategory.prototype.maxRows = function() {return 1;};
Window_IntelCategory.prototype.maxItems = function() {return $gameParty.IntelList.IntelCategories.length + 1;};

Window_IntelCategory.prototype.update = function() {
    Window_HorzCommand.prototype.update.call(this);
    if (this._topicWindow) {
        var index = this.index();
        this._topicWindow.setCategory(this.currentSymbol());
    }
};
 
Window_IntelCategory.prototype.makeCommandList = function() {
    this.addCommand("All", 'all');
    for (var index = 0; index < $gameParty.IntelList.IntelCategories.length; index++) {
        var result = $gameParty.IntelList.IntelCategories[index];
        this.addCommand(result, result);
    }
};
 
Window_IntelCategory.prototype.processCursorMove = function() {
    if (this.isCursorMovable()) {
        var lastIndex = this.index();
        if (Input.isRepeated('down')) {
            this.deselect();
        }
        if (Input.isRepeated('up')) {
            this.deselect();
        }
        if (Input.isRepeated('right')) {
            this.cursorRight(Input.isTriggered('right'));
        }
        if (Input.isRepeated('left')) {
            this.cursorLeft(Input.isTriggered('left'));
        }
        if (!this.isHandled('pagedown') && Input.isTriggered('pagedown')) {
            this.deselect();
        }
        if (!this.isHandled('pageup') && Input.isTriggered('pageup')) {
            this.deselect();
        }
        if (this.index() !== lastIndex) {
            SoundManager.playCursor();
        }
    }
};
 
/*----------------------------------------------------------------------------*/  
//Window for the list of topics.
function Window_IntelTopics() {this.initialize.apply(this, arguments);}
Window_IntelTopics.prototype = Object.create(Window_Selectable.prototype);
Window_IntelTopics.prototype.constructor = Window_IntelTopics;

Window_IntelTopics.prototype.initialize = function(x, y, width, height, contentsWindow, categoryWindow) {
Window_Selectable.prototype.initialize.call(this, x, y, width, height);
    this._category = 'all';
    this._data = [];
    this._contentsWindow = contentsWindow;
    this._categoryWindow = categoryWindow;
};

Window_IntelTopics.prototype.windowWidth = function() {
    return Math.floor(Graphics.boxWidth * 0.25);
};

Window_IntelTopics.prototype.windowHeight = function() {
    return Graphics.boxHeight;
};

Window_IntelTopics.prototype.maxCols = function() {return 1;};
Window_IntelTopics.prototype.maxItems = function() {return this._data ? this._data.length : 1; };
Window_IntelTopics.prototype.itemWidth = function() {return Math.floor(Graphics.boxWidth * 0.25) - this.textPadding() *2; };

Window_IntelTopics.prototype.item = function() {
    var index = this.index();
    return this._data && index >= 0 ? this._data[index] : null;
};

Window_IntelTopics.prototype.setCategory = function(category) {
    if (this._category !== category) {
        this._category = category;
        this.refresh();
        this.resetScroll();
    }
};

Window_IntelTopics.prototype.refresh = function() {
    this.makeIntelList();
    this.createContents();
    this.drawAllTopics();
};

Window_IntelTopics.prototype.makeIntelList = function() {
    if (this._category && this._category !== 'all') {
        this._data = $gameParty.IntelList.IntelItems.getIntelFromCategory(this._category);
    } else {
        this._data = $gameParty.IntelList.IntelItems;
    }
};

Window_IntelTopics.prototype.drawAllTopics = function() {
    this.makeIntelList();
    for (var index = 0; index < this._data.length; index++) {
        var intel = this._data[index];
        if (intel && this.maxItems() > index) {
            var rect = this.itemRect(index);
            rect.width -= this.textPadding();
            this.drawText(intel.topic, rect.x, rect.y, rect.width);
        }
    }
};

Window_IntelTopics.prototype.processCursorMove = function() {
        if (this.isCursorMovable()) {
        var lastIndex = this.index();
        if (Input.isRepeated('down')) {
            this.cursorDown(Input.isTriggered('down'));
        }
        if (Input.isRepeated('up')) {
            this.cursorUp(Input.isTriggered('up'));
        }
        if (Input.isRepeated('right')) {
            this.deselect();
            if (!this._categoryWindow.active) {
                this._categoryWindow.activate();
                this._categoryWindow.select(0);
            }
        }
        if (Input.isRepeated('left')) {
            this.deselect();
            if (!this._categoryWindow.active) {
                this._categoryWindow.activate();
                this._categoryWindow.select(0);
            }
        }
        if (!this.isHandled('pagedown') && Input.isTriggered('pagedown')) {
            this.cursorPagedown();
        }
        if (!this.isHandled('pageup') && Input.isTriggered('pageup')) {
            this.cursorPageup();
        }
        if (this.index() !== lastIndex) {
            SoundManager.playCursor();
        }
    }
    var index = this.index();
    var intel = this._data[index];
    if (intel  && this._contentsWindow) {
        this._contentsWindow.drawContents(intel.contents, intel.pic);
    }
};

Window_IntelTopics.prototype.activate = function() {
    this.active = true;
    this.select(0);
};
/*----------------------------------------------------------------------------*/
//Window to display the contents.
function Window_IntelContents() {this.initialize.apply(this, arguments);}
Window_IntelContents.prototype = Object.create(Window_Base.prototype);
Window_IntelContents.prototype.constructor = Window_IntelContents;

Window_IntelContents.prototype.initialize = function(x, y, width, height) {
    Window_Base.prototype.initialize.call(this, x, y, width, height);
};

Window_IntelContents.prototype.standardFontSize = function() { return 20;};
Window_IntelContents.prototype.lineHeight = function() { return 28;};
Window_IntelContents.prototype.textPadding = function() {return 4;};

Window_IntelContents.prototype.drawContents = function(contentsArray, picLoc) {
    this.contents.clear();
    var linesAbove = 0;
    var indent = 0;
    if (picLoc) { indent = Window_Base._faceWidth; };
    for (var x = 0; x < contentsArray.length; x++) {
        var contentsText = "    " + contentsArray[x];
        while (contentsText && contentsText.length > 0) {
            if (linesAbove * this.lineHeight() > Window_Base._faceHeight) {
                indent = 0;
            }
            var index = contentsText.length;
            while (this.contents.measureTextWidth(contentsText.slice(0, index)) + indent > this.contentsWidth()) {
                index = contentsText.slice(0, index).lastIndexOf(" ");
            }  
            this.contents.drawText(contentsText.slice(0, index), indent, linesAbove *this.lineHeight() - this.contentsHeight()/2, this.contentsWidth() - indent, this.height, 'left');
            contentsText = contentsText.slice(index);
            linesAbove++;
        }
    }
};
My primary question would be how to get the sorting function to work properly (I've tried using a specific category, so the problem isn't related to this.currentSymbol()).
I'd also appreciate it if someone could show me how to set things up such that the menu system behaves like the Item menu, so that the Window_IntelCategory.prototype.processCursorMove overwrite wasn't necessary.
EDIT: The processCursorMove problems were resolved in the previous thread.
 
Last edited:

Clock Out

Veteran
Veteran
Joined
Jun 14, 2016
Messages
92
Reaction score
45
First Language
English
Primarily Uses
RMMV
I get a "Type Error cannot read property id of null" message when clicking Intel on the main menu. Looks like DataManager.getIntelData()runs a loop now where the counter is initialized to 0. Should I remove the null value from my JSON file for future editions of the plugin or is that a bug?
 

Camkitsune

Veteran
Veteran
Joined
Mar 9, 2017
Messages
34
Reaction score
4
First Language
English
Primarily Uses
RMMV
Should I remove the null value from my JSON file for future editions of the plugin or is that a bug?
I removed the need for a null entry; appologies for not mentioning it, I've been trying to clean everything up in between bouts of trying to get the menu functionality working.
This should be the last thread I need to start for this plugin unless the in-game alerts prove to be too difficult to manage.

EDIT: The issue was actually a very silly mistake on my part; the issue was created because I was mistakenly trying to run the getIntelFromCategory function from IntelList.IntelItems .

Code:
Window_IntelTopics.prototype.makeIntelList = function() {
    if (this._category && this._category !== 'all') {
        this._data = $gameParty.IntelList.IntelItems.getIntelFromCategory(this._category);
    } else {
        this._data = $gameParty.IntelList.IntelItems;
    }
};
This code was broken, because IntelItems is just an array, and the getIntelFromCategory function was attached to the IntelList object. Fixing this to just $gameParty.IntelList.IntelItems.getIntelFromCategory results in the code operating correctly.
 
Last edited:

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

Latest Threads

Latest Posts

Latest Profile Posts

People1.png & SF_People1.png added!!!!

Adventurer:
"Why your body looks like a bird?"

Stranger:
"Because I'm harpy"

Adventurer:
"Clap along if you feel like a room without a roof"

*Both dancing to Pharrell Williams song*
Stream will be live shortly with a make-up session of the Interactive Text Adventure! Feel free to drop by!
Pootscooter wrote on Pharonix's profile.
Hey @Pharonix, just wondering what you're up to lately and if you've had an opportunity to check out the LTBS thread in the past few days...(a couple of us could really use your expertise). Hope you are well and Happy Thanksgiving!

Forum statistics

Threads
105,506
Messages
1,014,261
Members
137,173
Latest member
zoetsoi
Top