Visual indicators of complex hidden effects

There are multiple abilities in FCQ that rely on complex formulas. For example, Focus Strike is an ability that boosts your physical damage according to how much MP you have remaining.

While you could look at your remaining MP amount and try to calculate the resulting damage boost, that’s impractical. So I’ve started using state indicators to show the bonus damage as a percentage.

Character swinging staff at a slime foe while an indicator shows +20%

The icon art isn’t final, but it’s a good step in the right direction!

Consolidating the job tree

I got rid of the Hunter line and consolidated their most interesting skills into the other jobs. Here’s why…

I recently watched video gameplay of a MOBA, and I admired the well-defined roles of each character class. In that genre, the most common roles are DPS, Tank, and Support.

Single-player RPGs tend to allow more complexity in their character roles, perhaps because of their solo nature; with no team depending on you to play well, there is no urgency to understand each character.

In FCQ, each job has a unique theme. They broadly fall into the same categories mentioned above, but there are outliers.

  • Brawler line: Physical fighters/Tanks
  • Medic line: Buff/Heals
  • Thief line: Debuffs
  • Page line: Magic DPS
  • Adventurer line: Quirky non-standard skill costs, mix of physical fighters and buffs

As for the¬†Hunter/Ranger/Sage line of jobs… I don’t know what describes them. Each had radically different abilities, with little to connect them. I liked the idea of a class focused on bows and traps, so the Hunter was one of my favourites thematically. But I was never satisfied with the other two classes, nor their tenuous connection to each other.

Hunter skills are now gone (sadly).

Page now has the buffs from the Ranger.

Grandmaster has weather-changing from Sage.

Adding Pixelate Filter to RPG Maker MV 1.3.4

Pixels are cool if you’re a nerd.

I was using a plugin that created a pixelated effect on demand. But after updates to RPG Maker MV (and the Pixi library it’s based on), the plugin broke. When the original plugin writer updated the plugin, they removed the pixelate functionality altogether.

So I went on a search to bring back my crunchy pixels.

A good alternative

I discovered this wonderful library of filters for Pixi v4.

Once again, the pixelate functionality was broken. But Github user jeff-gold-marblemedia posted a quick fix.

Bringing that fix into the main code, and then pairing down the features I didn’t need, I ended up with a handy plugin.

The code

/*:
* @plugindesc v1.0.6 Pixelate filter for Pixi v4.
* @author pixi-filters https://github.com/pixijs/pixi-filters
* @help
* pixi-filters https://github.com/pixijs/pixi-filters
* Developers can make use of the filter like so:
* var filter = new PIXI.filters.PixelateFilter();
* filter.pixelSize = 50;
*/

/*!
* pixi-filters - v1.0.6
* Compiled Wed Aug 31 2016 08:40:25 GMT-0400 (EDT)
*
* pixi-filters is licensed under the MIT License.
* http://www.opensource.org/licenses/mit-license
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.filters = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({8:[function(require,module,exports){ // @see https://github.com/substack/brfs/issues/25 /** * This filter applies a pixelate effect making display objects appear 'blocky'. * * @class * @extends PIXI.AbstractFilter * @memberof PIXI.filters */ function PixelateFilter() { PIXI.Filter.call(this, // vertex shader "#define GLSLIFY 1
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;

uniform mat3 projectionMatrix;

varying vec2 vTextureCoord;

void main(void)
{
 gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
 vTextureCoord = aTextureCoord;
}", // fragment shader "#define GLSLIFY 1
varying vec2 vTextureCoord;

uniform vec4 filterArea;
uniform float pixelSize;
uniform sampler2D uSampler;

vec2 mapCoord( vec2 coord )
{
 coord *= filterArea.xy;
 coord += filterArea.zw;

 return coord;
}

vec2 unmapCoord( vec2 coord )
{
 coord -= filterArea.zw;
 coord /= filterArea.xy;

 return coord;
}

vec2 pixelate(vec2 coord, vec2 size)
{
 return floor( coord / size ) * size;
}

vec2 getMod(vec2 coord, vec2 size)
{
 return mod( coord , size) / size;
}

float character(float n, vec2 p)
{
 p = floor(p*vec2(4.0, -4.0) + 2.5);
 if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y)
 {
 if (int(mod(n/exp2(p.x + 5.0*p.y), 2.0)) == 1) return 1.0;
 }
 return 0.0;
}

void main()
{
 vec2 coord = mapCoord(vTextureCoord);

 // get the rounded color..
 vec2 pixCoord = pixelate(coord, vec2(pixelSize));
 pixCoord = unmapCoord(pixCoord);

 vec4 color = texture2D(uSampler, pixCoord);

 // determine the character to use
 float gray = (color.r + color.g + color.b) / 3.0;

 float n = 65536.0; // .
 if (gray > 0.2) n = 65600.0; // :
 if (gray > 0.3) n = 332772.0; // *
 if (gray > 0.4) n = 15255086.0; // o
 if (gray > 0.5) n = 23385164.0; // &
 if (gray > 0.6) n = 15252014.0; // 8
 if (gray > 0.7) n = 13199452.0; // @
 if (gray > 0.8) n = 11512810.0; // #

 // get the mod..
 vec2 modd = getMod(coord, vec2(pixelSize));

 gl_FragColor = color;

}"
);
  this.pixelSize = 4;
}

PixelateFilter.prototype = Object.create(PIXI.Filter.prototype);
PixelateFilter.prototype.constructor = PixelateFilter;
module.exports = PixelateFilter;

Object.defineProperties(PixelateFilter.prototype, {
  /**
   * This a point that describes the size of the blocks.
   * x is the width of the block and y is the height.
   *
   * @member {PIXI.Point}
   * @memberof PIXI.filters.PixelateFilter#
   */
  pixelSize: {
    get: function () {
      return this.uniforms.pixelSize;
    },
    set: function (value) {
      this.uniforms.pixelSize = value;
    }
  }
});

},{}],16:[function(require,module,exports){
// Require built filters
var filters = {
  PixelateFilter: require('./pixelate/PixelateFilter')
};

// Assign to filters
Object.assign(PIXI.filters, filters);

// Export for requiring
if (typeof module !== 'undefined' & amp; & amp; module.exports) {
  module.exports = filters;
}
},{"./pixelate/PixelateFilter":8}]},{},[16])(16)
});

Using the filter… for nerds

Chances are there’s a bit of vestigial nonsense near the end. My lack of familiarity with the way Pixi/Node works mean that I can’t optimize it much. But it’s working in all my use cases.

Toss this into a Scene_Map method to apply it. Putting it to good use is up to you.

this.pixelateFilter = new PIXI.filters.PixelateFilter();
this.pixelateFilter.pixelSize = 20;
this.children[0].filters = [this.pixelateFilter];

Expanding on Ranger skills

As a rule, all classes in FCQ are limited to 4 active skills.

This is a design constraint to keep each skill useful. In FCQ, you won’t have the equivalent of a level 1 Fire spell cluttering your skill list after you’ve learned the much superior level 3 Firaga.

It also keeps battles feeling snappy. Find your skills in 2 clicks. No scrolling required.

Equally important, this restriction is also to keep me sane. Even with only 4 skills to a class, but over 20 classes, that’s still a lot of skills. It’s plenty of work to conceptualize and balance them all.

With one exception

However, there was one area where this limitation felt… well, too limiting. My Ranger class has the ability to manipulate the elements. Since there are 4 elements, there are 4 related skills. That’s all. Just 4 support skills that are identical, except for their elemental affinity.

My workaround, while staying true to the rules, is to give the Ranger a toggle skill. Using Desert Camo or Swamp Camo will swap between two sets of 4 moves each.

  • Embed (elemental support)
  • Submerge (elemental support)
  • Ambush (new)
  • Desert Camo (toggle)

and

  • Parch (elemental support)
  • Levitate (elemental support)
  • Survival (new)
  • Swamp Camo (toggle)

A decent compromise

It’s slightly clunkier than just putting more than 4 skills in a scrolling list, since it takes a couple seconds to use the toggle skills. But I’m willing to accept that speed-bump since it keeps the menu behaviour consistent and gives the class a unique quirk.

Changes to dual-wielding

Dual-wielding is the concept of holding a weapon in each hand instead of a weapon and a shield, or a two-handed weapon. It’s a fun way to give your characters more options for customization. The problem with the way RPG Maker MV handles dual wielding is that there’s no visual feedback from it. Your attack animation still only hits one time, no matter how many weapons you hold.

Plugin woes

I’ve been using a plugin to fix this issue. But it’s been giving me grief, randomly changing my character’s stats between each weapon swing and leaving them permanently altered. The plugin’s support was shaky anyway, so rather than spend time troubleshooting, I looked for an alternative.

A practical solution

RPG Maker forums user Arkzein shared a code snippet using Yanfly’s action sequences to simulate a proper dual-wielding effect.

It does what it should quite elegantly, allowing the user to swing each weapon individually and letting those hits have different strengths depending on the weapon’s strength. I added a few extra features to it, including

  • a check to see if the weapon fires long-distance, or if the player should approach their target before the attack begins.
  • a check to see if the user is carrying two weapons (so it acts like a regular one-hit attack for users with one weapon).
  • a check to see if the 2nd weapon has a different animation than the first (otherwise it just repeats the first animation).

Sample code

Here’s the snippet in full:


// M.o.v.e. forward a little i.f. firing a missile
if user.attackMotion() == 'missile'
  move user: forward, 48, 10
  wait for move
else
// M.o.v.e. to the target
  move user: target, front base, 10
  wait for move
end

// I.f. the user has multiple weapons + dual-wield
if user.weapons().length > 1 && user.isStateAffected(129)
 EVAL: user._weap1 = user.weapons()[0];
 EVAL: user._weap2 = user.weapons()[1];
 // Unequips second weapon
 EVAL: user.forceChangeEquip(1, null);

 // 1st weapon attack
 MOTION ATTACK: user
 MOTION WAIT: user
 action animation
 wait for animation
 action effect

 EVAL: user.forceChangeEquip(0, user._weap2);

 // 2nd weapon attack
 MOTION ATTACK: user
 MOTION WAIT: user
 // animation of 2nd weapon
 EVAL: target.startAnimation(user.weapons()[0].animationId);
 wait for animation
 action effect

 // Restores weapons
 EVAL: user.forceChangeEquip(0,  user._weap1);
 EVAL: user.forceChangeEquip(1, user._weap2);

else
 // Regular 1 weapon attack
 MOTION ATTACK: user
 MOTION WAIT: user
 action animation
 wait for animation
 action effect
end

The weird dots in the comments are because action sequences don’t have the concept of comments. So if I didn’t put dots in between the letters of “i.f.” it would be interpreted as a programmatic if statement.

Merging updated scripts

The developers supporting RPG Maker MV (the engine behind FCA) released a fairly significant bug into the code with version 1.3.2. It relates to the way skills are learned, and since that’s a significant factor in the gameplay of FCA, I decided to refrain from updating my codebase.

Updating to 1.3.4

They just recently fixed the bug. So I went through and updated all of the core scripts (from 1.3.1 to 1.3.4) and all of Yanfly’s scripts.

To my surprise, FCA still boots up properly and I’m even seeing a huge improvement in how battles perform (better frame rate). But I’m seeing more stuttering on the regular map screen.

Time to run the rest of my tests and see what’s broken!

Variety in the weather

Even arid mountain cities get rain.

Pyr is going to have ash falling most of the time. But there’s a 4% chance of a rain happening for a little while.

Screenshot of game character outside in the rain

It’s tough to see the rain in a still image. Take my word for it.

New menu layout

new-menu-1

Full EXP and JP:

new-menu-2

This new layout is very dense with information. But as someone who has spent many hours grinding in Final Fantasy 5, checking the menu to see my character’s current JP is very convenient.

I’m debating whether or not to keep the larger text for the current HP and MP. Technically it’s not very important to draw the player’s eye to these values, since they are refilled after each battle. I may put this layout into the battle UI, and change this menu to have a current-only value.