Miscellaneous Plugins [SFG]

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
319
Reaction score
130
First Language
English
Primarily Uses
RMMV
Miscellaneous Plugins

I've posted a few plugins in the Plugin Request forum already, so I thought it would be a good idea to gather them all in one place. This thread will only be for small and simple plugins - if I release something big or complex I'll create another thread.

This is just a collection of utility functions that I use in several of my plugins. If you have any trouble getting one of my plugins to work, install this and make sure it's placed above any of my plugins.

Download Link

This allows you to set additional states to be treated as a death state for purposes of targeting, game overs, or both. You can also set an auto-state for 0 MP.

Download Link

This adds an option in the Options menu to set auto-battle for all actors. Turn it on and the game will do all your fights for you.

Download Link

This lets you use balloon icons in battle. Attach them to side-view actors or to enemies.

Download Link

This allows triggering an event while in an airship and also adds a way for events to have a "line of sight" that will trigger them when you step on a tile in the same row or column.

Download Link

This is a mod of Zeriab_ExtraMaps. It works pretty much the same way; the only real difference is that when you switch map folders, it loads the MapInfos.json from the new folder, which is required for compatibility with some of my plugins such as SFG_Localization and SFG_MapHierarchy.

Download Link

Makes maps inherit optional properties (currently BGM, BGS, and battle backs) from their parent map in the editor map hierarchy. Note: This could cause some lag when transferring between maps, especially if you have deep nesting and/or are deploying to the web. I didn't experience any lag in my testing, but your mileage may vary.

Download Link

This lets you shake the screen or play weather effects in the middle of a battle animation. Should work even when calling the battle animation from the map.

Download Link

Adds an option in the Options menu to disable all actor faces in message windows. You can override the setting for individual messages if you wish.

Download Link

Adds an additive trait for parameters, instead of the standard multiplicative trait.

Download Link

Allows you to control how items, weapons, armours, and skills are ordered in various windows. Useful if the lists in your database are not in any logical order.

Download Link

This adds a new command for eventing that lets you check the value of a variable and run code depending on what the value is. Programmers may know this as a "switch statement". Here's a contrived example of its use:

Code:
◆Control Variables:#0019 += 1
◆Plugin Command:switch @19
◆Show Choices:1, 2, 3, #4~8, 9, 10 (Window, Right, #1, #2)
:When 1
  ◆Text:None, Window, Bottom
  :Text:First time!
  ◆
:When 2
  ◆Text:None, Window, Bottom
  :Text:Second time!
  ◆
:When 3
  ◆Text:None, Window, Bottom
  :Text:Third time!
  ◆
:When #4~8
  ◆Text:None, Window, Bottom
  :Text:Maybe you should stop this...
  ◆
:When 9
  ◆Text:None, Window, Bottom
  :Text:Calm down, that's already nine times!
  ◆
:When 10
  ◆Text:None, Window, Bottom
  :Text:And now it's your tenth time!
  ◆
:End
◆Show Choices:#(value % 5 == 1), 20, >30 (Window, Right, #1, -)
:When #(value % 5 == 1)
  ◆Text:None, Window, Bottom
  :Text:I'm really at a loss for words.
  ◆Plugin Command:switch @19
  ◆Show Choices:>100, >45 (Window, Right, #1, #2)
  :When >100
    ◆Text:None, Window, Bottom
    :Text:Are you serious!? You've exceeeded one hundred!!!
    ◆
  :When >45
    ◆Text:None, Window, Bottom
    :Text:No really, stop it!
    ◆
  :End
  ◆
:When 20
  ◆Text:None, Window, Bottom
  :Text:Twentieth time already!? Are you mad!?
  ◆
:When >30
  ◆Text:None, Window, Bottom
  :Text:More than thirty times! Just... just stop!
  ◆
:When Cancel
  ◆Text:None, Window, Bottom
  :Text:This is starting to get crazy...
  ◆
:End
And another example using strings:

Code:
◆Name Input Processing:Harold, 8 characters
◆Plugin Command:switch $gameActors.actor(1).name()
◆Show Choices:"Harold", #"x"~"zzzzzzz", ~"[aeiou]{3,}" (Window, Right, #1, -)
:When "Harold"
  ◆Text:None, Window, Bottom
  :Text:The default, good choice!
  ◆
:When #"x"~"zzzzzzz"
  ◆Text:None, Window, Bottom
  :Text:That's quite a rare name...
  ◆
:When ~"[aeiou]{3,}"
  ◆Text:None, Window, Bottom
  :Text:So many vowels!
  ◆
:When Cancel
  ◆Text:None, Window, Bottom
  :Text:Not a bad choice!
  ◆
:End
Download Link

Adds wait commands for various event commands that have an optional wait. The most useful of this is "waitForMovementRoute", which will wait for a given character's movement route to complete. This lets you set the movement route going, do other stuff while it executes, but later wait for it to complete. If you're having movement routes cut short due to fast-forward, this can fix it.

Download Link

An add-on for TAA_BookMenu that will load your books from external text files, one file per book. Note: this does not work for web deployment at this time and may not work on mobile either - it requires NwJS in order to function.

To enable it, set DataSource Type to Book Files in the TAA_BookMenu configuration.


For some reason the forum wouldn't let me attach this file, so here's the full code - just paste it into a file called SFG_BookFiles.js.
JavaScript:
/*:
@plugindesc [v1.0] Load your books from dedicated book files instead of the Plugin Manager or JSON.
@author Solar Flare Games

@param directory
@text Books Directory
@desc The directory under data/ to load books from. All .txt files in this directory will be loaded as books.
@type text
@default books/

@param catDirs
@text Categories as Subdirectories
@desc Whether or not to use subdirectories as categories. If false, subdirectories are ignored.
@type boolean
@default true

@param catOrder
@text Category Order
@desc Specifies the sort order for the categories.
@type text[]
@default []

@param bkgnd
@text Backgrounds
@desc Specifies custom backgrounds for each of your books.
@type struct<BookBkgnd>[]

@param inline
@text Inline Images
@desc List images included with %img so that Exclude Unused Files knows about them.
@type file[]
@require 1
@dir img/pictures/
@default []

@help

This is an addon to TAA_BookMenu which allows you to load your books from
dedicated book files rather than a set of JSON files or directly from the
Plugin Manager.

For each book, create a simple .txt file with the book's contents. The filename
will be used as the book's key for ReadBook and other commands, with any spaces
stripped out. By default, it will also become the book's title.

Be warned: if you plan to deploy to the web or mobile, this plugin is not
guaranteed to work.

Also note: Even if you use subdirectories as categories, you need to make sure
that books in different directories do not have the same name!

A book file consists of two sections. The first section contains configuration
details about the book, while the second section consists of the book's
actual content. The two sections are separated by a line containing
three or more hyphens, like this:

---------

The configuration section consists of a series of "key: value" pairs, one
per line. The following keys can be used:

• title: Sets the book's title
• titleColor: Corresponds to Title Window Text Color
• category: Specifies the book's category
• id: Specifies the book's sorting key; if left out, books will be sorted
  alphabetically by their key (filename).

You cannot set custom backgrounds in the file. This is done to suppoort the
Exclude Unused Files option in RMMV deployment. Instead, you set custom
backgrounds here in the Plugin Manager. The Backgrounds parameter is a list
of possible backgrounds, each of which also has a list of books which it should
be used for - use the book's filename without the .txt extension.

If you want the same background on two books but with a different mode, you
can add that background to the list multiple times without issue. However,
do note that if you specify the same book on more than one background entry,
only the first will take effect.

*//*~struct~BookBkgnd:

@param books
@text Books
@desc The books to apply this background to.
@type text[]
@default []

@param bkgnd
@text Custom Background
@desc Specifies the custom background to use for these books.
@type file
@require 1
@dir img/pictures/

@param mode
@text Custom Background Mode
@desc Define how the custom image should be used for these books.
@type select
@option Detached Text Window Only
@value 5
@option Detached Title + Text Window
@value 9
@option Menu Text Window Only
@value 6
@option Menu Title + Text Window
@value 10
@option All Text Window Only
@value 7
@option All Title + Text Window
@value 11
@default 11

*/

(function() {
    var params = PluginManager.parameters('SFG_BookFiles');
    var backgrounds = Utils.parseRecursive(params.bkgnd);

    const readBooksFromDirectory = function(dir, mode) {
        let fs_base = require('fs'), util = require('util');
        // This works around Node being old and lacking the 'fs/promises' module.
        let fs = {
            exists: util.promisify(fs_base.exists),
            stat: util.promisify(fs_base.stat),
            readdir: util.promisify(fs_base.readdir),
            readFile: util.promisify(fs_base.readFile),
        };
        fs.exists(dir).then(exists => {
            if(!exists) return; // No books to load...
            return fs.stat(dir);
        }).then(stat => {
            if(!stat.isDirectory()) return; // No books to load...
            return fs.readdir(dir);
        }).then(dirListing => {
            if(dirListing.length == 0) return; // No books to load...
            let stats = [];
            for(let i = 0; i < dirListing.length; i++) {
                let path = dir + dirListing[i];
                stats.push(fs.stat(path).then(stat => {
                    return {
                        file: dirListing[i],
                        path: path,
                        isDir: stat.isDirectory(),
                    };
                }));
            }
            return Promise.all(stats);
        }).then(files => {
            if(mode == '?categories') {
                files = files.filter(f => f.isDir);
                for(let i = 0; i < files.length; i++) {
                    let path = files[i].path;
                    if(!path.endsWith('/')) path += '/';
                    readBooksFromDirectory.call(this, path, files[i].file);
                }
                return [];
            } else {
                files = files.filter(f => !f.isDir).map(f => f.path);
                let data = [];
                for(let i = 0; i < files.length; i++) {
                    data.push(fs.readFile(files[i], 'utf8').then(data => {
                        return {
                            file: files[i].replace(/.*\//g, ''),
                            path: files[i],
                            data: data,
                        };
                    }))
                }
                return Promise.all(data);
            }
        }).then(files => {
            if(files.length == 0) return; // No books to load...
            for(let i = 0; i < files.length; i++) {
                let file = files[i].file;
                let data = files[i].data.split(/^-{3,}\r?\n/m);
                if(data.length > 2) {
                    console.warn('More than one section separator in book file %1'.format(file))
                }
                let book = {
                    id: 0, customBg: '', titleColor: 0,
                    title: file.replace('.txt', ''),
                    category: mode === '?all' ? params.unknownCategory : mode,
                };
                let header = data[0], bookKey = file.replace(/\s+/g, '').replace('.txt', '');
                // Backgrounds...
                for(let j = 0; j < backgrounds.length; j++) {
                    if(backgrounds[j].includes(bookKey)) {
                        let bg = backgrounds[j];
                        book.customBg = bg.bkgnd;
                        book.customBgMode = bg.mode;
                        break;
                    }
                }
                book.text = data.slice(1).join('------').replace(/\r\n/g, '\n');
                for(let line of header.split('\n')) {
                    let m = line.match(/^([a-z]+):(.*)$/im);
                    if(m) {
                        let key = m[1].trim().toLowerCase(), value = m[2].trim();
                        if(key === 'category' && mode !== '?all') continue;
                        book[key] = value;
                    }
                }
                this._books[bookKey] = book;

                // Create category subobject
                if(!this._bookKeyByCategory[book.category]) {
                    this._bookKeyByCategory[book.category] = [];
                }
                if(!this._booksRead[book.category]) {
                    this._booksRead[book.category] = [];
                }

                // Fill in books under categories ordered by IDs
                if(this._bookKeyByCategory[book.category][book.id] === undefined) {
                    if(!this._bookKeyByCategory[book.category].contains(bookKey))
                        this._bookKeyByCategory[book.category][book.id] = bookKey;
                } else {
                    if(!this._bookKeyByCategory[book.category].contans(bookKey))
                        this._bookKeyByCategory[book.category].push(bookKey);
                }

                if(!this._categoryByBookKey[bookKey])
                    this._categoryByBookKey[bookKey] = book.category;
            }
            this._doneLoading = true;
        });
    };

    const old_loadBooks = LibraryData.prototype.loadBookData;
    LibraryData.prototype.loadBookData = function() {
        if(this._source === 'Book Files') {
            if(!Utils.isNwjs()) {
                throw Error("Node not available, can't load books!");
            }
            let dir = 'data/%1'.format(params.directory);
            if(!dir.endsWith('/')) dir += '/';
            this._bookKeyByCategory = {}
            this._booksRead = {};
            this._books = {};
            this._categoryByBookKey = {};
            this._doneLoading = false;
            readBooksFromDirectory.call(this, dir, params.catDirs ? '?categories' : '?all');
            this._categoryList = JSON.parse(params.catOrder);
            this._bookTitleObject = "title";
            this._bookMenuTitleColorObject = "titleColor";
            this._bookTextObject = "text";
            this._bookCategoryObject = "category";
            this._bookIdObject = "id";
            // TODO: Set custom backgrounds from params.bkgnd...
        } else old_loadBooks.call(this);
    };
})();

Terms of Use

  • You don't need to credit me in the game credits or anything. However, don't remove me from the "author" field in the plugin file.
  • You can use these plugins in commercial or non-commercial games, free of charge.
  • Feel free to modify these plugins however you need for your game. Exception: Do not modify SFG_Utils for any reason. If you need something added to or altered in SFG_Utils, just create a new plugin.
  • If a plugin that I created is not listed in this thread, these terms of use do not apply to it.
 

Attachments

Last edited:

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
319
Reaction score
130
First Language
English
Primarily Uses
RMMV
Added SFG_AutoBattle to the first post.
 

Moon_Haven

Veteran
Veteran
Joined
May 5, 2020
Messages
36
Reaction score
14
First Language
English
Primarily Uses
RMMV
Hi Solar Flare, and thank you for sharing these!

With regards to Auto Battler, I see that you are applying the flag to all the battlers. How would you recommend that I modify the code to have 3 options:

Auto Battle = OFF
Auto Battle = PARTIAL (Followers Only)
Auto Battle = ALL

I was thinking:

if OFF: all battlers == OFF
if PARTIAL: actor (0) == OFF and for i=1 to 8, actor(i) == ON
if ALL: all battlers ON == OFF
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
319
Reaction score
130
First Language
English
Primarily Uses
RMMV
Well, that makes it more complicated, certainly... but if you only wanted the ON setting to never apply to actor 1, you could change line 43 to the following:

JavaScript:
return (this.actorId() != 1 && ConfigManager.autoBattle) || Game_BattlerBase.prototype.isAutoBattle.call(this);
In case you're using an editor without line numbers, this is near the bottom of the file, and its content in the original plugin (which you would delete) is:

JavaScript:
return ConfigManager.autoBattle || Game_BattlerBase.prototype.isAutoBattle.call(this);
Making it three options though will take more work for two reasons - first, by default the options window is set to only handle on/off parameters (so anything that's not on/off requires special handling), and second, it probably requires implementing some note tags. Neither of these are very difficult, but they're not a simple quick modification either.

I'll let you know if I get around to implementing it. Until then, you can use the plugin either as released (ON = all battlers, OFF = none) or with the above modification (ON = all battlers except lead, OFF = none).
 

Moon_Haven

Veteran
Veteran
Joined
May 5, 2020
Messages
36
Reaction score
14
First Language
English
Primarily Uses
RMMV
See, I though the options window would allow for integer or text, not just booleans. That's a bummer because I had a few ideas in mind which are going to be a pain to implement because of this limitation.

Anyways, thanks for the info, I'll start working on that.
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
319
Reaction score
130
First Language
English
Primarily Uses
RMMV
You can add more options than just booleans, it's just extra work because the window assumes anything other than the volume settings are boolean values. I've done the work in another plugin so I know more or less what would need to be done, it's just a question of what to prioritize.
 

Blair Pendragon

Veteran
Veteran
Joined
Jul 15, 2012
Messages
100
Reaction score
44
First Language
English
Primarily Uses
For autobattle, what separates this from the in game version?
nvm im stupid, forgot the part it said "in the options menu" lol.
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
319
Reaction score
130
First Language
English
Primarily Uses
RMMV
Yes, it's the same as the in-game version, but just adds it to the options menu. :)
 

Mojo907

Veteran
Veteran
Joined
May 21, 2013
Messages
154
Reaction score
35
First Language
English
Primarily Uses
RMMV
I Ilke the plugins you off here, and auto battle really touches my inner lazy child, and while I enjoy its inclusion I was wondering if it would be just as nice to have it included in the battle commands much like yanfly's ace autobattle?
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
319
Reaction score
130
First Language
English
Primarily Uses
RMMV
You mean you want to turn it on and off in the middle of a battle?
 

Mojo907

Veteran
Veteran
Joined
May 21, 2013
Messages
154
Reaction score
35
First Language
English
Primarily Uses
RMMV
You mean you want to turn it on and off in the middle of a battle?
Yes, I was thinking some battles you may come across you may find can be handled easily without tasking yourself to fighting it manually like 4 slimes, and you just autobattle it.

However the next battle could be a war party of humans or something that will require a bit more tactical skill, and you can opt not to autobattle.
 
Last edited:

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
319
Reaction score
130
First Language
English
Primarily Uses
RMMV
So, it would be more of a "fight just this one battle for me" option, is that correct? At the party command you'd have an auto-battle option in addition to Fight and Escape, and choosing that would make the engine fight that battle for you, but in the next battle you'd have control again? Would you want to be able to swap it back off in the middle of the battle?
 

Mojo907

Veteran
Veteran
Joined
May 21, 2013
Messages
154
Reaction score
35
First Language
English
Primarily Uses
RMMV
So, it would be more of a "fight just this one battle for me" option, is that correct? At the party command you'd have an auto-battle option in addition to Fight and Escape, and choosing that would make the engine fight that battle for you, but in the next battle you'd have control again? Would you want to be able to swap it back off in the middle of the battle?
I suppose most would want the option per turn, I'm more inclined to turn it on in the middle of battle at any time, but once it is on the engine finishes the fighting. Each battle begins as normal with the option to switch over to auto battle within the battle command block in addition to Fight and Escape.
 

Moon_Haven

Veteran
Veteran
Joined
May 5, 2020
Messages
36
Reaction score
14
First Language
English
Primarily Uses
RMMV
[...] and auto battle really touches my inner lazy child
It's more than just the inner child. There's plenty of autobattlers on mobile games. It's a niche, of course, but some of them are actually pretty darn good (check Soda Dungeon).
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
319
Reaction score
130
First Language
English
Primarily Uses
RMMV
Updated SFG_AltDeathState. Adds a new parameter, and Auto Remove doesn't work the same way as before (plus it seems like its meaning was backwards in the previous version).

I couldn't find a consistent way to get the behaviour I originally envisioned for Auto Remove, which was that the state would only go away if you gained MP and explicitly removed the state at the same time. The problem is that "at the same time" simply doesn't exist in the engine.
 

Mojo907

Veteran
Veteran
Joined
May 21, 2013
Messages
154
Reaction score
35
First Language
English
Primarily Uses
RMMV
A quick extra note, could it be possible to make AutoBattle be compatible with Yanfly's Options Core? I mean as far as being able to show up in the options menu
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
319
Reaction score
130
First Language
English
Primarily Uses
RMMV
I don't know anything about OptionsCore, but if it doesn't already work with my plugin placed below OptionsCore, I think it's likely not trivial to make it work. I'm also not interested in making plugin-specific patches for compatibility (like checking for things another plugin does and whether the plugin is enabled to change how I do things).

However, if OptionsCore offers a way to add custom options similar to how MainMenuManager works, you can probably make use of that to add the option. The option text would be TextManager.optionAutoBattle, and the value of the option is ConfigManager.autoBattle.
 

Mojo907

Veteran
Veteran
Joined
May 21, 2013
Messages
154
Reaction score
35
First Language
English
Primarily Uses
RMMV
I don't know anything about OptionsCore, but if it doesn't already work with my plugin placed below OptionsCore, I think it's likely not trivial to make it work. I'm also not interested in making plugin-specific patches for compatibility (like checking for things another plugin does and whether the plugin is enabled to change how I do things).

However, if OptionsCore offers a way to add custom options similar to how MainMenuManager works, you can probably make use of that to add the option. The option text would be TextManager.optionAutoBattle, and the value of the option is ConfigManager.autoBattle.
I believe it does have a way to nest it in there, I wasn't well versed on what I would need to do to make it work. I'll try that thanks!

EDIT: apparently.....I suck at making things happen....
 
Last edited:

Blair Pendragon

Veteran
Veteran
Joined
Jul 15, 2012
Messages
100
Reaction score
44
First Language
English
Primarily Uses
Updated SFG_AltDeathState. Adds a new parameter, and Auto Remove doesn't work the same way as before (plus it seems like its meaning was backwards in the previous version).

I couldn't find a consistent way to get the behaviour I originally envisioned for Auto Remove, which was that the state would only go away if you gained MP and explicitly removed the state at the same time. The problem is that "at the same time" simply doesn't exist in the engine.
Well a work around for us would be to just make every action in the game, which heals mp, also remove the buff.
(pretty much how death should have worked. leave the state removal to us, where we have to manually pick which states get removed from death, rather than it defaulting to removal of all states)
If this wouldnt work for any reason, is it possible to make an adjustment, so manual removal is possible?

EDIT: forgot MP regeneration, which would require an immunity, but doesnt quite work properly this way. (unless you put that in the spells description)

So MP restoration items/abilities naturally remove the state, and the MP regen has an immunity.
 

Moon_Haven

Veteran
Veteran
Joined
May 5, 2020
Messages
36
Reaction score
14
First Language
English
Primarily Uses
RMMV
I believe it does have a way to nest it in there, I wasn't well versed on what I would need to do to make it work. I'll try that thanks!

EDIT: apparently.....I suck at making things happen....
This will surely help you:
You can check out Driftwood tutorial


But to save you some trouble, here's the menu option that you need to have:

Annotation 2020-06-20 084632.png
 
Last edited:

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

Latest Threads

Latest Profile Posts

Automatic level scaling without an option to turn it off can be a very bad choice for a game. The worst I've ever seen was in Nightmare of Druaga, where if a power outage made your system turn off, the game detects it as an attempted cheat and overwrites your save while taking away your best gear, leaving you unable to progress at the late stages of the game, and unable to recover.
Problem with sequels: Heroes getting rid of all their items and forgets all of their skills within the span of a year without explanation. :kaomad3:
I can see the end of my prologue. Perfect time to decide to pull everything over into MZ, right? Right?!
Excited to be nearing the end of setting up my own custom Point-And-Click system template! Just need to iron out some kinks, get an input text system going, add animations to buttons, and then finalize my button-mashing event system and it'll be complete >:3c
AlcTheHero wrote on Mystic_Enigma's profile.
hi.

Forum statistics

Threads
99,643
Messages
967,612
Members
131,312
Latest member
jacob_rev
Top