| Je vous propose un petit set de 3 plugins qui ont trait aux combats dans MV. Il ne s’agit pas d’un système de combat, ils agissent plutôt sur les étapes qui précèdent le combat.
C’est un set de trois plugins qui peuvent tous fonctionner seuls ou ensemble.
Par ordre de chargement dans la liste des plugins (du haut vers le bas) :
1) 808troopCondition.js
Un plugin qui permet de filtrer les troupes ennemies qu’il est possible de rencontrer selon divers paramètres.
2) 808BattleFrequency.js
Une autre façon gérer la fréquence de combats aléatoire, notamment en incluant la différence entre le niveau du groupe et la dangerosité de la zone traversée.
3) 808BattleTransition.js
Un effet de transition façon fragmentation et éclatement de l’écran au moment ou un combat se déclenche.
Les trois plugins se trouvent tout en bas de ce post.
Dans le détail :
-808troopCondition
Spoiler (cliquez pour afficher) L’intérêt de ce plugin est de donner plus de souplesse aux conditions de rencontre de groupes d’ennemis spécifiques, selon la région ou le terrain traversé ou encore le niveau moyen du groupe.
Cela peut s’appliquer pour un type de créatures qui n’apparait que sur l’eau peu profonde par exemple.
Mais aussi sur une carte très large sur laquelle beaucoup d’ennemis de niveaux différents coexistent, comme une carte du monde par exemple.
On peut par exemple couper la carte en zone distinctes par niveau (les monstres forts sur les régions 1 à 10 et les monstres moyens en zone 11 à 20 par exemple).
MV accepte déjà les régions pour les monstres mais limité à 3 régions uniquement. Quant aux terrains ou au niveau du groupe, ces conditions ne sont pas disponibles.
Fonctionnement :
Dans l’onglet troupes de MV, dans la première page de l’évènement de troupe, insérez un commentaire avec les tags appropriés :
<region: 1, 5-7>
Dans ce cas, les groupe d’ennemi n’apparaitra que lorsque le joueur traverse les régions 1, 5, 6, 7.
<terrain: 3>
Les ennemis sur la page desquels se trouve ce commentaire ne pourront être rencontrés que lorsque le joueur traverse une case avec le terrain ID 3.
<terrain: 2-4>
Les ennemis sur la page desquels se trouve ce commentaire ne pourront être rencontrés que lorsque le joueur traverse une case avec le terrain ID 2 ou 3 ou 4.
<plevel: 80-99>
Le groupe d’ennemis ainsi tagué ne pourra surgir que si l’équipe est en moyenne d’un niveau compris entre 80 et 99.
Si aucun des tags ci-dessus n’est présent, le groupe ennemi non tagué sera géré par le moteur d’origine de RPG Maker MV. C’est-à-dire :
Troupe ID1 = Molosse *1
Je ne mets aucun commentaire au molosse.
Troupe ID 2 = Squelette *1
Je marque le Squelette avec un commentaire : <region : 6>
Troupe ID 3 = Dragonnet *1
J’insère en commentaire <region : 4-6>
<plevel : 10-99>
Je place le joueur sur une carte qui est peinte avec un mix de « pas de région », et de cases peintes avec les régions 1 à 5.
Dans les propriétés de cette carte, je liste les troupes ennemies qui peuvent être croisées. ID 1 + 2
+ 3
Je donne à chacune le même poids 10, et je paramètre leur présence possible sur la carte entière.
-Le Molosse sera susceptible d’apparaitre à chaque rencontre car il n’a aucun commentaire.
-Le Squelette n’apparaitra jamais, parce qu’il ne se rencontre que lorsque le joueur est sur la région 6 qui n’existe pas sur ma carte.
-Le Dragonnet quant a lui se rencontrera sur les cases de région 4 ou 5, à condition que le groupe soit de niveau 10 ou plus.
Le poids des troupes est pris en compte dans les probabilités d’apparition depuis les propriétés de la carte, la méthode par défaut est conservée sur ce point.
-808BattleFrequency
Spoiler (cliquez pour afficher) Un plugin qui modifie la fréquence des combats aléatoires en rendant la probabilité très faible lors des premiers pas et de plus en plus importante au fur et a mesure que de nouveaux déplacements sont effectués sans avoir de combat aléatoire.
Le niveau des joueurs est aussi pris en compte et la fréquence s’en trouve diminué quand le groupe est trop fort pour la région traversée, ou augmentée lorsque le groupe se trouve dans une zone de plus haut niveau.
En gros, un compteur de danger augmente à chaque pas « compté ».
Le compteur de danger est remis à zéro en entrant sur une nouvelle carte ou après un combat.
Il peut aussi être remis à zéro au besoin avec une commande de plugin :
BattleFrequency reset
La valeur de la probabilité de rencontre aléatoire varie en fonction de ce compteur (et donc du nombre de pas) ainsi que du modificateur de zone (influencé par la différence entre le niveau de danger la zone traversée et le niveau du groupe).
A chaque contrôle de fréquence, un nombre aléatoire est généré. Si ce nombre est inférieur à la probabilité de rencontre, un combat se déclenche.
Le paramètre Step Check Interval (valeur de 1 par défaut) correspond au nombre de pas entre lesquels un contrôle est effectué. Quand sa valeur est de 1, le moteur contrôlera si un combat a lieu à chaque pas. Si sa valeur est de 2, la probabilité d’un combat sera effectuée lors d’un pas sur deux.
Les cartes peuvent éventuellement être taguées dans le champ Note avec un Step Check comme ceci :
<stepCheck 2>
Avec ce tag, les rencontres sur cette carte ne seront possibles qu’une fois tous les deux pas.
Si la carte comporte cette note, elle prendra le pas sur la valeur du paramètre de plugin Step Check.
En d’autres termes, le paramètre de Step Check n’est utile que sur les cartes qui n’ont pas de Step check note.
L’intérêt de cette fonction est de changer la fréquence donnée pour un certain nombre de pas. Cela peut être utile dans certains cas :
Par exemple, une map sur laquelle le héros se déplace plus vite. A ce moment-là, le paramètre de plugin pourrait être de 1 et le tag de la carte de 2, pour équilibrer la fréquence de combat sur la carte ou le héros se déplace plus vite.
Ou encore, sur une carte qui utilise le déplacement de base de MV (un pas = 1 case), le Step Check sera de 1. Et sur d’autre cartes avec un pixel mouvement, par exemple qui permet de se déplacer à l’intérieur d’une case en 3 ou 4 pas, on donnera a cette carte un Step Check de 3 ou 4 pour ramener la fréquence de combat au même niveau que la carte du monde, soit un check par case.
Les cartes aussi doivent impérativement être taguées dans leur champs Note avec la valeur de la Zone de Danger.
On peut rentrer une valeur fixe si elle est bonne pour toute la carte. Par exemple dans un donjon de niveau 10 :
<zoneDanger 10>
Ou alors on peut utiliser les régions comme zone de danger avec:
<zoneDanger region>
A ce moment-là, en marchant sur la région 14, la fréquence de combat sera calculée pour une zone de niveau 14, le temps du passage sur cette case.
Attention, si la carte n’est pas marquée avec une valeur de Zone de Danger, aucune rencontre aléatoire n’aura lieu, puisque la zone de danger sera considérée comme ayant une valeur de 0 et introduira cette valeur dans la formula de rencontre aléatoire.
Voici l’effet que les différences entre niveau du groupe et niveau de la zone de danger auront sur la formule de rencontres :
Petite différence de niveau (Équipe de niveau 3 dans une zone de niveau 2) :
• levelDiff = -1
• weightFactor ≈ 0,10
• dangerModifier ≈ 0,97
• Résultat : 97 % du taux de rencontres normal
Différence de niveau moyenne (Équipe de niveau 50 dans une zone de niveau 45) :
• levelDiff = -5
• weightFactor ≈ 0,25
• dangerModifier ≈ 0,94
• Résultat : 94 % du taux de rencontres normal
Grande différence de niveau (Équipe de niveau 3 dans une zone de niveau 99) :
• levelDiff = 96
• weightFactor ≈ 19,13
• dangerModifier = 4,0 (capé par la limite)
• Résultat : 400 % du taux de rencontres normal
Différence de niveau extrême (Équipe de niveau 99 dans une zone de niveau 3) :
• levelDiff = -96
• weightFactor ≈ 19,13
• dangerModifier = 0,25 (capé par la limite)
• Résultat : 25 % du taux de rencontres normal
-808BattleTransition
Celui-ci est tout simple ! Il s’agit d’un effet de morcellement de l’écran au moment ou un combat se lance, pour une transition un peu plus stylée que l’écran blanc d’origine.
Codes à insérer dans un document texte, à renommer en .js et à placer dans le projet dans jsplugins:
A renommer 808TroopCondition.js:
Spoiler (cliquez pour afficher)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
| // File: 808TroopCondition.js
/*:
* @plugindesc v1.3 Enhanced troop encounter selection with region, terrain, and party level filters.
* @version 1.3
* @author mugen808
*
* @param Debug
* @type boolean
* @desc Set to true to enable console logs for debugging.
* @default false
*
* @help
* This plugin enhances troop selection by applying conditional filters based on
* map regions, terrain tags, and party level ranges. It is designed to work
* independently of encounter frequency calculations.
*
* Troop Note Tags (add to a troop's first event page comments):
* <region: x[, y, z, a-e]> - Specifies allowed region IDs.
* <terrain: w[, x-z]> - Specifies allowed terrain tags.
* <plevel: min-max> - Specifies the range of party levels required
* for the troop to appear.
*
* Example:
* <region: 1, 2, 5-8> - Troop appears in regions 1, 2, 5, 6, 7, 8.
* <terrain: 1-3> - Troop appears on terrain tags 1, 2, and 3.
* <plevel: 5-10> - Troop appears when the party level is between
* 5 and 10.
*
* Compatibility:
* - When using this plugin (808TroopCondition) with 808BattleFrequency,
* place this plugin **above** 808BattleFrequency in the plugin list.
* This ensures that troop filtering is applied after encounter frequency
* calculations.
* Permission: Free to use, do not repost, do not claim yours.
*/
(function() {
'use strict';
const PLUGIN_NAME = '808TroopCondition';
const parameters = PluginManager.parameters(PLUGIN_NAME);
const DEBUG_MODE = parameters['Debug'].toLowerCase() === 'true';
window.Imported = window.Imported || {};
window.Imported[PLUGIN_NAME] = true;
//=============================================================================
// * Constants and Utility Functions
//=============================================================================
const TAG_PATTERNS = {
REGION: /<region:s*([d,-s]+)>/i,
TERRAIN: /<terrain:s*([d,-s]+)>/i,
LEVEL: /<plevel:s*(d+)-(d+)>/i
};
class TroopConditionUtils {
static parseNumberRange(str) {
if (!str) return [];
const result = new Set();
const parts = str.split(',').map(p => p.trim());
for (const part of parts) {
if (part.includes('-')) {
const [start, end] = part.split('-').map(n => parseInt(n));
if (!isNaN(start) && !isNaN(end)) {
for (let i = Math.min(start, end); i <= Math.max(start, end); i++) {
result.add(i);
}
}
} else {
const num = parseInt(part);
if (!isNaN(num)) {
result.add(num);
}
}
}
return Array.from(result).sort((a, b) => a - b);
}
static getPartyAverageLevel() {
const members = $gameParty.battleMembers();
if (!members.length) return 1;
const total = members.reduce((sum, actor) => sum + actor.level, 0);
return Math.floor(total / members.length);
}
static getTroopConditions(troopId) {
const conditions = {
regions: [],
terrains: [],
levelRange: [0, 999],
hasConditions: false
};
const troop = $dataTroops[troopId];
if (!troop || !troop.pages || !troop.pages[0] || !troop.pages[0].list) return conditions;
const comments = troop.pages[0].list
.filter(cmd => cmd.code === 108 || cmd.code === 408)
.map(cmd => cmd.parameters[0]);
for (const comment of comments) {
// Region check
const regionMatch = comment.match(TAG_PATTERNS.REGION);
if (regionMatch) {
conditions.regions = this.parseNumberRange(regionMatch[1]);
conditions.hasConditions = true;
}
// Terrain check
const terrainMatch = comment.match(TAG_PATTERNS.TERRAIN);
if (terrainMatch) {
conditions.terrains = this.parseNumberRange(terrainMatch[1]);
conditions.hasConditions = true;
}
// Level check
const levelMatch = comment.match(TAG_PATTERNS.LEVEL);
if (levelMatch) {
const min = parseInt(levelMatch[1]);
const max = parseInt(levelMatch[2]);
if (!isNaN(min) && !isNaN(max)) {
conditions.levelRange = [Math.min(min, max), Math.max(min, max)];
conditions.hasConditions = true;
}
}
}
return conditions;
}
static getEligibleTroops(currentRegion, currentTerrain, partyLevel) {
const encounters = $gameMap.encounterList();
if (!encounters || encounters.length === 0) return null;
const eligibleTroops = [];
let totalWeight = 0;
// Check each encounter entry
for (const encounter of encounters) {
const troopId = encounter.troopId;
const weight = encounter.weight;
const conditions = this.getTroopConditions(troopId);
// Check if troop meets all conditions
const regionValid = conditions.regions.length === 0 ||
conditions.regions.includes(currentRegion);
const terrainValid = conditions.terrains.length === 0 ||
conditions.terrains.includes(currentTerrain);
const levelValid = partyLevel >= conditions.levelRange[0] &&
partyLevel <= conditions.levelRange[1];
if (regionValid && terrainValid && levelValid) {
eligibleTroops.push({ troopId, weight });
totalWeight += weight;
}
}
return { eligibleTroops, totalWeight };
}
static selectWeightedTroop(eligibleData) {
if (!eligibleData || eligibleData.eligibleTroops.length === 0) return 0;
const { eligibleTroops, totalWeight } = eligibleData;
let random = Math.random() * totalWeight;
for (const troop of eligibleTroops) {
random -= troop.weight;
if (random <= 0) {
return troop.troopId;
}
}
// Fallback to first eligible troop if something goes wrong
return eligibleTroops[0].troopId;
}
}
//=============================================================================
// * Troop Selection Override
//=============================================================================
const _Game_Player_makeEncounterTroopId = Game_Player.prototype.makeEncounterTroopId;
Game_Player.prototype.makeEncounterTroopId = function() {
const currentRegion = this.regionId();
const currentTerrain = $gameMap.terrainTag(this.x, this.y);
const partyLevel = TroopConditionUtils.getPartyAverageLevel();
// Get all eligible troops with their weights
const eligibleData = TroopConditionUtils.getEligibleTroops(
currentRegion,
currentTerrain,
partyLevel
);
// If no eligible troops found, return 0 to skip battle
if (!eligibleData || eligibleData.eligibleTroops.length === 0) {
if (DEBUG_MODE) {
console.log('No eligible troops found for current conditions:', {
region: currentRegion,
terrain: currentTerrain,
partyLevel: partyLevel
});
}
return 0;
}
// Select a troop based on weights from eligible troops
const selectedTroopId = TroopConditionUtils.selectWeightedTroop(eligibleData);
if (DEBUG_MODE) {
console.log('Selected troop from eligible pool:', {
selectedTroopId: selectedTroopId,
eligibleCount: eligibleData.eligibleTroops.length,
totalWeight: eligibleData.totalWeight
});
}
return selectedTroopId;
};
})(); |
A renommer 808BattleFrequency.js
Spoiler (cliquez pour afficher)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
| // File: 808BattleFrequency.js
/*:
* @plugindesc v1.2 Custom encounter frequency system for RPG Maker MV
* @version 1.2.0
* @author mugen808
*
* @param stepCheck
* @text Step Check Interval
* @desc Frequency of encounter checks (in steps).
* 0 = no checks, 1 = every step, 2 = every two steps, etc.
* @default 1
*
* @param Debug
* @type boolean
* @desc Set to true to enable console logs for debugging.
* @default false
*
* @help
* This plugin calculates encounter frequency based on a custom danger
* counter system and incorporates party level into encounter frequency.
*
* It allows for a more dynamic frequency of encounters based on party level
* relative to the area’s "danger level," or zone difficulty.
* This system does not affect troop selection or eligibility.
*
*==========================================================================
* Key Concepts:
* - **Danger Counter**: The danger counter increases with each step the
* player takes and resets after each battle. The higher this value,
* the higher the chance of a battle. The counter starts at 0, ensuring
* the first step after entering an area will not immediately trigger
* a battle. Each additional step raises the danger counter, gradually
* increasing the odds of an encounter.
*
* - **Zone Danger**: Zone danger reflects the difficulty of an area. The
* plugin uses the zone danger value relative to the party’s average
* level to influence encounter frequency.
* - A zone danger roughly equal to the party’s level results in a
* typical encounter frequency.
* - A zone danger much higher than the party’s level will lead to
* frequent encounters.
* - For instance, in a level 99 max system, a danger level of 99 produces
* normal encounter frequency for a level 99 party and high frequency for
* a level 25 party. A very high zone danger, such as 400, results in
* frequent encounters regardless of party level.
*
* **Party Level Adjustment**: The plugin’s main feature is to use party level
* to adjust encounter rates, so:
*
* - Low-level parties in high-level zones face frequent encounters.
* - High-level parties in low-level zones encounter fewer enemies.
* - Players in zones matching their party level experience standard encounter
* rates.
*
*==========================================================================
* Plugin Command:
* - `BattleFrequency reset`span style="color:#7cc4f5;"> : Resets the danger counter to 0.
* Note: This is automatically done once a battle completes or after leaving
* or entering a map.
*
*==========================================================================
* Map Notetag:
* - <zoneDanger x>: Sets a fixed zone danger value for the map.
* Example: <zoneDanger 18>
* - <zoneDanger region>: Uses the region ID as the zone danger value.
* Note:
* -If a zone danger value is not set in the map properties, the danger
* value will default to 0, preventing any encounters from being
* triggered on that map.
*
* - <stepCheck x>: Sets the step check interval for encounters (in steps).
* For example, <stepCheck 3> checks every 3 steps, while
* <stepCheck 1> checks every step.
* <stepCheck 1> means four times more encounter than <stepCheck 4>
* Notes:
* -The stepCheck interval value entered in a map note field will override
* the value set in the plugin parameter stepCheck. In other words, the
* parameter will only work in maps that do not have a stepCheck note
* tag.
*
* -This could be useful to lower or increase the encounter frequency
* in certain maps that need to have the same Zone Danger value.
* This is also useful if some maps use some sort of pixel movement
* while other maps use regular movement to ensure consistency between
* battle frequency.
* -Example: On the world map, we have MV's default movement system where
* one tile equals one step, while in dungeons, we use a pixel movement
* plugin where one tile equals three steps. In this case, set your
* stepCheck parameter to 3 and tag the world map with
* <stepCheck 1> for consistent encounter frequency across all maps.
*
*==========================================================================
* Compatibility:
* - When using this plugin (808BattleFrequency) alongside 808TroopCondition,
* place this plugin **beneath** 808TroopCondition in the plugin list.
* This order ensures that troop filtering conditions are applied before the
* encounter frequency calculations.
*
*--------------------------------------------------------------------------
*==========================================================================
* Encounter Formula Documentation:
*
*## Overview
* The encounter system uses a sophisticated formula that takes into account
* the party's level, the zone's danger level, and the accumulated danger
* counter to determine encounter chances. The system is designed to provide
* more nuanced encounter rates based on the difference between party level
* and zone difficulty.
*
*## Encounter Calculation Workflow
* - Each valid step adds 1024 to the danger counter.
* - Encounter checks occur based on the stepCheck interval.
* - At each check, a 0-255 random number is generated and compared to the
* calculated encounter chance. Battles will be triggered if that random
* number is inferior to the encounter chances.
* - The debug mode will display all calculation details for testing.
*
*## Core Formula Components
*
*### 1. Base Calculations
*
* levelDiff = zoneDanger - partyLevel
* absLevelDiff = |levelDiff| (absolute value)
*
*### 2. Weight Factor
*
* weightFactor = (absLevelDiff / 15 + 1)^1.5 - 1
*
* This creates a curve that:
* - Minimally impacts encounters when level differences are small
* - Moderately scales for medium level differences
* - Significantly impacts encounters for large level differences
*
*### 3. Direction Modifier
*
* direction = sign(levelDiff) // Returns 1 if zone is higher, -1 if party
* is higher. This simply affects the danger modifier based on whether the
* zone danger or party level is higher.
*
*### 4. Final Danger Modifier
*
* dangerModifier = clamp(1.0 + (direction * weightFactor * 0.25), 0.25, 4.0)
*
* Starting from a base value of 1.0 (100% normal rate), the formula adjusts
* the encounter rate based on level differences while maintaining reasonable
* bounds.
*
*### 5. Encounter Chance Calculation
*
* encounterChance = clamp(dangerCounter * dangerModifier / 256, 0, 256)
*
*## Example Outcomes
*
* 1. **Small Level Difference** (Level 3 party in level 2 zone):
* - levelDiff = -1
* - weightFactor ≈ 0.10
* - dangerModifier ≈ 0.97
* - Result: 97% of normal encounter rate
*
* 2. **Medium Level Difference** (Level 50 party in level 45 zone):
* - levelDiff = -5
* - weightFactor ≈ 0.25
* - dangerModifier ≈ 0.94
* - Result: 94% of normal encounter rate
*
* 3. **Large Level Difference** (Level 3 party in level 99 zone):
* - levelDiff = 96
* - weightFactor ≈ 19.13
* - dangerModifier = 4.0 (capped)
* - Result: 400% of normal encounter rate
*
* 4. **Extreme Level Difference** (Level 99 party in level 3 zone):
* - levelDiff = -96
* - weightFactor ≈ 19.13
* - dangerModifier = 0.25 (capped)
* - Result: 25% of normal encounter rate
*
*## Formula Characteristics
*
* - **Non-Linear Scaling**: The weight factor uses a power function
* (^1.5) to create non-linear scaling
* - **Small Difference Handling**: Level differences under 5 have
* minimal impact on encounter rates (less than 5% deviation)
* - **Large Difference Handling**: Level differences over 20 have
* exponentially increasing impact
* - **Capped Modifiers**: Final encounter rates are capped between
* 25% and 400% of the base rate
* - **Smooth Transition**: The formula provides smooth transitions
* between different level ranges
*#######################################################################
* Permission: Free to use, do not repost, do not claim yours.
*/
(function() {
'use strict';
const PLUGIN_NAME = '808BattleFrequency';
const parameters = PluginManager.parameters(PLUGIN_NAME);
let stepCheck = Number(parameters['stepCheck'] || 1);
const DEBUG_MODE = parameters['Debug'].toLowerCase() === 'true';
//=============================================================================
// * Utility Functions
//=============================================================================
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
//=============================================================================
// * Game_Player modifications
//=============================================================================
const _Game_Player_initMembers = Game_Player.prototype.initMembers;
Game_Player.prototype.initMembers = function() {
_Game_Player_initMembers.call(this);
this.initBattleFrequencyMembers();
};
Game_Player.prototype.initBattleFrequencyMembers = function() {
this._dangerCounter = 0;
this._stepCounter = 0;
this._isInDangerZone = false;
};
Game_Player.prototype.resetDangerCounter = function() {
this._dangerCounter = 0;
this._stepCounter = 0;
};
// Gets the current zone danger from map notes
Game_Player.prototype.getCurrentZoneDanger = function() {
const note = $dataMap.note || '';
const match = note.match(/<zoneDangers+(d+|region)>/i);
if (!match) {
if (DEBUG_MODE) {
console.log('No zoneDanger tag found - plugin functionality paused');
}
this._isInDangerZone = false;
return null;
}
this._isInDangerZone = true;
if (match[1].toLowerCase() === 'region') {
return this.regionId();
}
return parseInt(match[1]);
};
// Party average level
Game_Player.prototype.getPartyAverageLevel = function() {
const members = $gameParty.battleMembers();
if (members.length === 0) return 1;
const totalLevels = members.reduce((sum, actor) => sum + actor.level, 0);
return Math.max(1, Math.floor(totalLevels / members.length));
};
// Step counting and encounter checks
const _Game_Player_increaseSteps = Game_Player.prototype.increaseSteps;
Game_Player.prototype.increaseSteps = function() {
_Game_Player_increaseSteps.call(this);
// Only process steps if in a danger zone
if (!this._isInDangerZone) return;
if (stepCheck <= 0) return;
this._stepCounter++;
if (this._stepCounter >= stepCheck) {
if (DEBUG_MODE) {
console.log(`nStep Count: ${this._stepCounter}, Danger Counter Before Increment: ${this._dangerCounter}`);
}
this.checkForBattleEncounter();
this._stepCounter = 0; // Reset step counter after check
this._dangerCounter = Math.min(this._dangerCounter + 1024, 262144); // danger counter increase +1024, cap 262144
if (DEBUG_MODE) {
console.log(`Danger Counter After Increment: ${this._dangerCounter}`);
}
}
};
Game_Player.prototype.checkForBattleEncounter = function() {
if (!this.canEncounter()) return;
const zoneDanger = this.getCurrentZoneDanger();
if (zoneDanger === null) return;
const partyLevel = this.getPartyAverageLevel();
const randomBattle = Math.floor(Math.random() * 256);
const levelDiff = zoneDanger - partyLevel;
const absLevelDiff = Math.abs(levelDiff);
const weightFactor = Math.pow(absLevelDiff / 15 + 1, 1.5) - 1;
const direction = Math.sign(levelDiff);
const dangerModifier = clamp(
1.0 + (direction * weightFactor * 0.25),
0.25, //minimum chances of encounter. 0.25 means 25% of normal chances. Will happen when party is high level in a low level zone.
4.0 //maximum chances of encounter. 4 means 400% of normal chances. Will happen when party is low level in a high level zone.
);
const encounterChance = clamp(this._dangerCounter * dangerModifier / 256, 0, 256);
const encounterPercentage = (encounterChance / 256) * 100; // For logging purpose only
if (DEBUG_MODE) {
console.log(`Zone Danger: ${zoneDanger}`);
console.log(`Party Average Level: ${partyLevel}`);
console.log(`Level Difference: ${levelDiff}`);
console.log(`Weight Factor: ${weightFactor}`);
console.log(`Final Danger Modifier: ${dangerModifier}`);
console.log(`Encounter Chance: ${encounterChance} / 256 (${encounterPercentage.toFixed(2)}%)`);
console.log(`Random Battle Roll: ${randomBattle}`);
}
if (randomBattle < encounterChance) {
this.initiateRandomEncounter();
}
};
// Checks if encounters are possible
Game_Player.prototype.canEncounter = function() {
return !$gameMap.isEventRunning() &&
$gameSystem.isEncounterEnabled() &&
!this.isInVehicle() &&
!this.isDebugThrough();
};
// Initiates the battle encounter
Game_Player.prototype.initiateRandomEncounter = function() {
this._dangerCounter = 0;
this._stepCounter = 0;
// Let the default system or other plugins handle troop selection
const troopId = this.makeEncounterTroopId();
if (DEBUG_MODE) {
console.log(`Selected Troop ID: ${troopId}`);
console.log(`Danger Counter Reset to: ${this._dangerCounter}`);
}
if (troopId > 0) {
BattleManager.setup(troopId, true, false);
BattleManager.onEncounter();
SceneManager.push(Scene_Battle);
} else {
if (DEBUG_MODE) {
console.log(`No valid troop found for encounter. Encounter skipped.`);
}
// Space left for handling cases when a battle is triggered but no troops qualify for the encounter.
// If this section is left empty, the battle will simply be skipped. Else, add the logic here.
}
};
const _BattleManager_endBattle = BattleManager.endBattle;
BattleManager.endBattle = function(result) {
_BattleManager_endBattle.call(this, result);
$gamePlayer.resetDangerCounter(); // Ensures danger counter resets to 0 after battle
};
//=============================================================================
// * Map Setup
//=============================================================================
Game_Map.prototype.getStepCheckValue = function() {
const note = $dataMap.note || '';
const match = note.match(/<stepChecks+(d+)>/i);
if (match) {
return Number(match[1]);
}
return stepCheck; // Fallback to default parameter
};
const _Game_Map_setup = Game_Map.prototype.setup;
Game_Map.prototype.setup = function(mapId) {
_Game_Map_setup.call(this, mapId);
stepCheck = this.getStepCheckValue();
$gamePlayer.resetDangerCounter();
// Force check of zone danger status on map load
$gamePlayer.getCurrentZoneDanger();
};
//=============================================================================
// * Plugin Commands
//=============================================================================
const _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args) {
_Game_Interpreter_pluginCommand.call(this, command, args);
if (command.toLowerCase() === 'battlefrequency') {
if (args[0].toLowerCase() === 'reset') {
$gamePlayer.resetDangerCounter();
}
}
};
//=============================================================================
// * Disable Original Encounter System
//=============================================================================
Game_Player.prototype.makeEncounterCount = function() {
this._encounterCount = Infinity; //Disable MV frequency calculation so that this plugin does not generate battles in addition to MV default encounter system, but rather instead of it.
};
})(); |
A nommer 808BattleTransition.js
Spoiler (cliquez pour afficher)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
| // File: 808BattleTransition.js
/*:
* @plugindesc Seamless Shatter Effect Battle Transition
* @author mugen808
*
* @help
* This plugin creates a shatter transition between map and battle scenes.
* The screen breaks into fragments that reveal the battle scene underneath
* when entering combat.
*
* **Compatibility**:
* - This plugin should be placed **below** the 808BattleFrequency and
* 808TroopCondition plugins in the plugin list.
* Permission: Free to use, do not repost, do not claim yours.
*/
(function() {
let transitionContainer = null;
class ShatterTransitionContainer extends PIXI.Container {
constructor() {
super();
this.fragments = [];
this.isActive = false;
this.battleSceneReady = false;
}
initialize(mapScene, battleScene) {
this.mapSnapshot = Bitmap.snap(mapScene);
this.battleScene = battleScene;
this.fragmentSize = 32;
this.createFragments();
this.isActive = true;
this.battleSceneReady = false;
}
createFragments() {
const width = Graphics.width;
const height = Graphics.height;
const columns = Math.ceil(width / this.fragmentSize);
const rows = Math.ceil(height / this.fragmentSize);
for (let row = 0; row < rows; row++) {
for (let col = 0; col < columns; col++) {
const x = col * this.fragmentSize;
const y = row * this.fragmentSize;
const fragment = new Sprite(this.mapSnapshot);
fragment.setFrame(x, y, this.fragmentSize, this.fragmentSize);
fragment.x = x + this.fragmentSize / 2;
fragment.y = y + this.fragmentSize / 2;
fragment.anchor.x = 0.5;
fragment.anchor.y = 0.5;
fragment.velocity = {
x: (Math.random() * 4) - 2,
y: -Math.random() * 6 - 2
};
fragment.rotationSpeed = (Math.random() * 0.1) - 0.05;
fragment.delay = Math.floor(Math.random() * 15);
fragment.fadeSpeed = Math.random() * 0.015 + 0.01;
fragment.scale.x = 1;
fragment.scale.y = 1;
// Add minimum lifespan to ensure visibility
fragment.minLifespan = 60 + Math.floor(Math.random() * 30); // 1~1.5 seconds at 60fps
fragment.lifetime = 0;
this.fragments.push(fragment);
this.addChild(fragment);
}
}
}
update() {
if (!this.isActive) return;
for (let i = this.fragments.length - 1; i >= 0; i--) {
const fragment = this.fragments[i];
if (fragment.delay > 0) {
fragment.delay--;
continue;
}
fragment.lifetime++;
fragment.x += fragment.velocity.x;
fragment.y += fragment.velocity.y;
fragment.velocity.y += 0.2;
fragment.rotation += fragment.rotationSpeed;
if (fragment.lifetime > fragment.minLifespan) {
fragment.opacity -= fragment.fadeSpeed * 255;
}
fragment.scale.x *= 0.99;
fragment.scale.y *= 0.99;
if (fragment.opacity <= 0 && fragment.lifetime > fragment.minLifespan) {
this.removeChild(fragment);
this.fragments.splice(i, 1);
if (this.fragments.length === 0) {
this.isActive = false;
if (this.parent) {
this.parent.removeChild(this);
}
transitionContainer = null;
break;
}
}
}
}
}
const _Scene_Map_startEncounterEffect = Scene_Map.prototype.startEncounterEffect;
Scene_Map.prototype.startEncounterEffect = function() {
_Scene_Map_startEncounterEffect.call(this);
transitionContainer = new ShatterTransitionContainer();
transitionContainer.initialize(this, SceneManager.nextScene);
this.addChild(transitionContainer);
};
const _Scene_Map_updateEncounterEffect = Scene_Map.prototype.updateEncounterEffect;
Scene_Map.prototype.updateEncounterEffect = function() {
_Scene_Map_updateEncounterEffect.call(this);
if (transitionContainer) {
transitionContainer.update();
}
};
const _Scene_Battle_create = Scene_Battle.prototype.create;
Scene_Battle.prototype.create = function() {
_Scene_Battle_create.call(this);
if (transitionContainer) {
this.addChild(transitionContainer);
}
};
const _Scene_Battle_update = Scene_Battle.prototype.update;
Scene_Battle.prototype.update = function() {
_Scene_Battle_update.call(this);
if (transitionContainer) {
transitionContainer.update();
}
};
})(); |
|