/*:
@author Coelocanth
@plugindesc Handle random encounters using events
Version 1.1.0
@target MZ
@help

Normally a random encounter on the map immediately starts a battle with the chosen
troop. With this plugin, you can instead call an event to handle the random encounter,
putting control of the game mechanics back in your hands, without needing to
re-implement everything in parallel events.

Setup:
Reserve a game variable to receive the troop ID chosen for a random encounter.
You can skip this step if you don't want to use the troop / region settings on maps
for random encounters.
This variable will be set to the troop ID encountered (0 if there were no valid troops)

To use a common event, configure the event ID in the plugin parameters, which will be
called whenever an event occurs.
Alternatively you may wish to use a map event - to do this, enable that option in the
plugin parameters; and add <when:encounter> to the event's note field.

Encounter Formula:
The default formula in all RPG makers is:
Math.randomInt(n) + Math.randomInt(n) + 1

This varies between 1 step and 200% of the map's encounter steps setting.
This gives rise the the "encounter every three steps" perception.

Some suggested alternatives:
(Math.randomInt(n) + Math.randomInt(n) + 1) / 2 + n / 2

This is the same distribution, but between 50% and 150% of the encounter steps

(Math.randomInt(n) + Math.randomInt(n) + Math.randomInt(n)) * 2 / 3 + 1

This is a bell curve distribution - very short or long number of steps are
possible but much less likely.

You can use any formula you like, as with damage formulas. When the formula is
evaluated, n is the map's encounter steps setting.

@param varTroopId
@text Variable for Troop ID
@desc If set, the specified variable will be set to the troop ID of the random encounter
@default 0
@type variable

@param commonEventId
@text Common Event
@desc If set, the specified common event will be called for encounters
@default 0
@type common_event

@param killSwitchId
@text Kill Switch
@desc If set, and the switch is ON, random encounters are handled by the default scripts
@default 0
@type switch

@param callMapEvent
@text Call Map Event
@desc If true, map events with the <when:encounter> note will be called.
@default false
@type boolean

@param encounterFormula
@text Encounter Formula
@desc script that will be evaluated to produce the steps until next encounter.
@default Math.randomInt(n) + Math.randomInt(n) + 1
*/

/*
ISC License

Copyright (c) 2020 Coelocanth

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
(function () {
    var _params = PluginManager.parameters("cc_random_encounters");
    var _varTroopId = parseInt(_params["varTroopId"]);
    var _commonEventId = parseInt(_params["commonEventId"]);
    var _killSwitchId = parseInt(_params["killSwitchId"]);
    var _callMapEvent = Boolean(_params["callMapEvent"] == "true");
    var _encounterFormula = _params["encounterFormula"];

    var _Game_Player_executeEncounter = Game_Player.prototype.executeEncounter;
    Game_Player.prototype.executeEncounter = function () {
        if(_killSwitchId && $gameSwitches.value(_killSwitchId)) {
            return _Game_Player_executeEncounter.call(this);
        }
        if (!$gameMap.isEventRunning() && this._encounterCount <= 0) {
            this.makeEncounterCount();
            var troopId = this.makeEncounterTroopId();
            if(_varTroopId) {
                $gameVariables.setValue(_varTroopId, troopId);
            }
            var anyEventCalled = false;
            if(_callMapEvent) {
                $gameMap.events().forEach(function(event) {
                    if(event.event().meta.when === 'encounter') {
                        if(!event._erased) {
                            event.start();
                            anyEventCalled = true;
                        }
                    }
                });
            }
            if(_commonEventId) {
                $gameTemp.reserveCommonEvent(_commonEventId);
                return false;
            }
            if(anyEventCalled) {
                return false;
            }
            // no event called, do a standard encounter
            if ($dataTroops[troopId]) {
                BattleManager.setup(troopId, true, false);
                BattleManager.onEncounter();
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    Game_Player.prototype.makeEncounterCount = function () {
        var n = $gameMap.encounterStep();
        try {
            this._encounterCount = eval(_encounterFormula);
        } catch (e) {
            console.log(e.stack);
            this._encounterCount = Math.randomInt(n) + Math.randomInt(n) + 1;
        }
    };

}());