├── Kru_AirshipEvents.js ├── Kru_AssignStats.js ├── Kru_BattleMovementFrames.js ├── Kru_Calendar.js ├── Kru_ClassChange.js ├── Kru_ClearMapPhotos.js ├── Kru_Core.js ├── Kru_Demo.js ├── Kru_ExtraMovementFramesPatch.js ├── Kru_GameSeed.js ├── Kru_LoadImageTypes.js ├── Kru_MapLoadEvents.js ├── Kru_MapMerge.js ├── Kru_MultitileEvents.js ├── Kru_PartyWindow.js ├── Kru_PipeMinigame.js ├── Kru_PreviousPosition.js ├── Kru_Reputation.js ├── Kru_SRD_FaceImages.js ├── Kru_SkillCore.js ├── Kru_SkillToggle.js ├── Kru_SkillTree.js ├── Kru_UserSwap.js ├── Kru_VariableText.js ├── Kru_VehicleInsides.js ├── LICENSE └── README.md /Kru_AirshipEvents.js: -------------------------------------------------------------------------------- 1 | /*: 2 | * Airship Events 3 | * 4 | * @plugindesc 1.0 Allows airships to interact with events. 5 | * 6 | * @author Krusynth 7 | * 8 | * @help 9 | * By default, RPG Maker MV doesn't allow airships to interact with events. 10 | * This plugin removes that limitation, allowing airships to land in towns, etc. 11 | * 12 | * Note that you'll have to create special handling for dealing with 13 | * transfers (e.g. entering towns, etc.) for airships to use this as 14 | * expected. The easiest way to achieve this is to add to your event 15 | * a Conditional Branch for Vehicle: Airship is driven and move the 16 | * transfer into the Else clause. 17 | * 18 | * Terms & Conditions 19 | * This plugin is MIT Licensed. (Free for non-commercial and commercial use.) 20 | */ 21 | 22 | var Imported = Imported || {}; 23 | Imported.Kru_AirshipEvents = 1.0; 24 | 25 | var Kru = Kru || {}; 26 | Kru.AE = {}; 27 | 28 | Kru.AE.Game_Player__canStartLocalEvents = Game_Player.prototype.canStartLocalEvents; 29 | 30 | Game_Player.prototype.canStartLocalEvents = function() { 31 | return true; 32 | }; 33 | 34 | Game_Player.prototype.forceOffVehicle = function() { 35 | this.setDirection(2); 36 | this._followers.synchronize(this.x, this.y, this.direction()); 37 | this.vehicle().getOff(); 38 | this.setTransparent(false); 39 | this._vehicleGettingOff = true; 40 | this.setMoveSpeed(4); 41 | this.setThrough(false); 42 | this.makeEncounterCount(); 43 | this.gatherFollowers(); 44 | }; -------------------------------------------------------------------------------- /Kru_AssignStats.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Assign Stats 3 | // Version: 1.0.1 4 | //============================================================================= 5 | /*: 6 | * @plugindesc v1.0.1 Allow players to assign stat points. 7 | * 8 | * @author Krusynth 9 | * 10 | * @help 11 | * ============================================================================ 12 | * Information 13 | * ============================================================================ 14 | * 15 | * Adds the ability for players to buy stat points instead of automatically 16 | * increasing stats on level up. 17 | * 18 | * @param Stat Points 19 | * @desc Number of points for stats to award per level 20 | * @default 4 21 | * 22 | * @param Initial Points 23 | * @desc Number of points for stats characters start with 24 | * @default 0 25 | * 26 | * @param Cost Per Stat 27 | * @desc Number of points it costs to raise a stat one point 28 | * @default 1 29 | * 30 | * @param Default Level Increase 31 | * @desc yes/no Use the default level-up increment for stats or only use point allocations? 32 | * @default yes 33 | * 34 | * Terms & Conditions 35 | * This plugin is free for non-commercial and commercial use. 36 | */ 37 | 38 | /* 39 | * TODO: 40 | * (Optional) indicator of unspent points per actor. 41 | * Make param list configurable. 42 | * Set a minimum level to allow the user to start customizing, so that new 43 | * players aren't overwhelmed. 44 | * Make initial points toggleable if Level == 1 or not. 45 | * Allow function for points per level. 46 | */ 47 | 48 | var Imported = Imported || {}; 49 | Imported.Kru_AssignStats = "1.0.0"; 50 | 51 | var Kru = Kru || {}; 52 | Kru.AS = { 53 | config: {}, 54 | Params: [ 55 | { 56 | name: function() { return TextManager.param(this.id); }, 57 | value: function(actor) { return actor.param(this.id); }, 58 | description: 'ATtacK power', 59 | param: 'atk', 60 | id: 2, 61 | assignable: true 62 | }, 63 | { 64 | name: function() { return TextManager.param(this.id); }, 65 | value: function(actor) { return actor.param(this.id); }, 66 | description: 'DEFense power', 67 | param: 'def', 68 | id: 3, 69 | assignable: true 70 | }, 71 | { 72 | name: function() { return TextManager.param(this.id); }, 73 | value: function(actor) { return actor.param(this.id); }, 74 | description: 'Magic ATtack power', 75 | param: 'mat', 76 | id: 4, 77 | assignable: true 78 | }, 79 | { 80 | name: function() { return TextManager.param(this.id); }, 81 | value: function(actor) { return actor.param(this.id); }, 82 | description: 'Magic DeFense power', 83 | param: 'mdf', 84 | id: 5, 85 | assignable: true 86 | }, 87 | { 88 | name: function() { return TextManager.param(this.id); }, 89 | value: function(actor) { return actor.param(this.id); }, 90 | description: 'AGIlity', 91 | param: 'agi', 92 | id: 6, 93 | assignable: true 94 | }, 95 | { 96 | name: function() { return TextManager.param(this.id); }, 97 | value: function(actor) { return actor.param(this.id); }, 98 | description: 'LUcK', 99 | param: 'luk', 100 | id: 7, 101 | assignable: true 102 | }, 103 | { 104 | name: "Max HP", 105 | value: function(actor) { return actor.mhp; } 106 | }, 107 | { 108 | name: "Max MP", 109 | value: function(actor) { return actor.mmp; } 110 | } 111 | ] 112 | }; 113 | 114 | Kru.AS.Parameters = PluginManager.parameters('Kru_AssignStats'); 115 | Kru.AS.Parameters['Initial Points'] = Number(Kru.AS.Parameters['Initial Points']); 116 | Kru.AS.Parameters['Cost Per Stat'] = Number(Kru.AS.Parameters['Cost Per Stat']); 117 | Kru.AS.Parameters['Default Level Increase'] = ( 118 | String(Kru.AS.Parameters['Default Level Increase']).toLowerCase() === 'yes' 119 | ); 120 | 121 | 122 | if(!Imported.Kru_Core) { 123 | alert("Kru_AssignStats requires Kru_Core."); 124 | throw new Error("Kru_AssignStats requires Kru_Core."); 125 | } 126 | 127 | /* 128 | * Setup our actors 129 | */ 130 | 131 | Kru.AS.DataManager_isDatabaseLoaded = DataManager.isDatabaseLoaded; 132 | DataManager.isDatabaseLoaded = function() { 133 | Kru.AS.DataManager_isDatabaseLoaded.call(this); 134 | return true; 135 | }; 136 | 137 | // Setup 138 | Kru.AS.Game_Actor_Setup = Game_Actor.prototype.setup; 139 | Game_Actor.prototype.setup = function (actorId) { 140 | Kru.AS.Game_Actor_Setup.call(this, actorId); 141 | if(typeof(this._statPoints) == 'undefined') { 142 | this._statPoints = Kru.AS.Parameters['Initial Points']; 143 | } 144 | if(typeof(this._statPointCostAmount) == 'undefined') { 145 | this._statPointCostAmount = []; 146 | } 147 | }; 148 | 149 | Game_Actor.prototype.snapshot = function() { 150 | return JSON.parse(JSON.stringify(this)); 151 | } 152 | 153 | // Level up 154 | Kru.AS.Game_Actor_levelUp = Game_Actor.prototype.levelUp; 155 | Game_Actor.prototype.levelUp = function () { 156 | let before = this.snapshot(); 157 | 158 | Kru.AS.Game_Actor_levelUp.call(this); 159 | let points = 0; 160 | let value = eval(Kru.AS.Parameters['Stat Points']); 161 | if(Number.isInteger(value)) { 162 | points += value; 163 | } 164 | this._statPoints += points; 165 | this.statLevelUp(before); 166 | }; 167 | 168 | Game_Actor.prototype.statLevelUp = function(before) { 169 | for(let i = 0; i < Kru.AS.Stats.length; i++) { 170 | if(Kru.AS.Stats[i].update) { 171 | Kru.AS.Stats[i].update(before, this); 172 | } 173 | } 174 | } 175 | 176 | Game_Actor.prototype.statPointCost = function(paramId) { 177 | if(typeof(this._statPointCostAmount[paramId]) != 'undefined') { 178 | return this._statPointCostAmount[paramId]; 179 | } 180 | else { 181 | return Kru.AS.Parameters['Cost Per Stat']; 182 | } 183 | }; 184 | 185 | if(!Kru.AS.Parameters['Default Level Increase']) { 186 | // Disable the level increase and reset back to base. 187 | Kru.AS.Game_Actor_paramBase = Game_Actor.prototype.paramBase; 188 | Game_Actor.prototype.paramBase = function(paramId) { 189 | return this.currentClass().params[paramId][1]; 190 | }; 191 | } 192 | 193 | function Scene_Status() { 194 | this.initialize.apply(this, arguments); 195 | } 196 | 197 | Scene_Status.prototype = Object.create(Scene_MenuBase.prototype); 198 | 199 | /* Skill Tree Window */ 200 | class Kru_StatusWindow extends Kru_CustomListWindow { 201 | initialize(win) { 202 | super.initialize(win); 203 | 204 | let lineHeight = this.lineHeight(); 205 | 206 | let params = this.getParams(); 207 | 208 | for (let i = 0; i < params.length; i++) { 209 | let item = params[i]; 210 | item.description = item.description || ''; 211 | item.location = item.location || this.getItemLocation(item, i); 212 | item.width = item.width || 200; 213 | item.height = item.height || (lineHeight + this.margin); 214 | 215 | this._data.push(item); 216 | } 217 | 218 | this.refresh(); 219 | 220 | this.select(0); 221 | } 222 | 223 | getItemLocation(item, i) { 224 | // TODO: Fix placement. 225 | let y = 50; 226 | let x = 10; 227 | let y2 = y + this.lineHeight() * i + this.margin * 2; 228 | 229 | return [x, y2]; 230 | } 231 | 232 | getParams() { 233 | let params = []; 234 | for(let i = 0; i < Kru.AS.Stats.length; i++) { 235 | if(Kru.AS.Stats[i].assignable) { 236 | params.push(Kru.AS.Stats[i]); 237 | } 238 | } 239 | 240 | return params; 241 | } 242 | 243 | drawItem(index) { 244 | let content = this._data[index]; 245 | let name = typeof content.name === 'function' ? content.name() : content.name; 246 | this.drawText(name, content.location[0], content.location[1], content.width - this.margin, 'left'); 247 | this.drawText(content.value(this.actor), content.location[0], content.location[1], content.width - this.margin, 'right'); 248 | } 249 | 250 | drawHeader() { 251 | // Character's name goes in the top left corner. 252 | this.contents.drawText(this.actor._name, 0, 10, 250, 10, 'left'); 253 | 254 | // Class goes on the right. 255 | this.changeTextColor(this.systemColor()); 256 | this.contents.drawText($dataClasses[this.actor._classId].name, 670, 10, 250, 10, 'right'); 257 | this.resetTextColor(); 258 | 259 | this.drawPassives(); 260 | } 261 | 262 | drawPassives() { 263 | // List our passive attributes on the right. 264 | 265 | // TODO: Fix placement. 266 | let y2 = 50 + this.margin * 2; 267 | let x = 520; 268 | 269 | this.contents.drawText( 270 | 'HP: ' + this.actor.hp + '/' + this.actor.mhp, 271 | 520, 75, 250, 10, 'left' 272 | ); 273 | this.contents.drawText( 274 | 'MP: ' + this.actor.mp + '/' + this.actor.mmp, 275 | 520, 110, 250, 10, 'left' 276 | ); 277 | } 278 | 279 | drawFooter() { 280 | let content = String(this.actor._statPoints) + ' Pts'; 281 | // Arbitrarily set this in the bottom right corner. 282 | this.contents.drawText(content, 670, 415, 100, 10, 'right'); 283 | } 284 | 285 | onOk() { 286 | let stat = this._data[this.index()]; 287 | let statCost = this.actor.statPointCost(stat.id); 288 | 289 | // Failure states. 290 | if(this.actor._statPoints < statCost) { 291 | return this.failState(); 292 | } 293 | 294 | let before = this.actor.snapshot(); 295 | 296 | this.addStatPoint(stat.id, 1); 297 | this.actor._statPoints -= statCost; 298 | 299 | this.actor.statLevelUp(before); 300 | 301 | this.refresh(); 302 | this.activate(); 303 | } 304 | 305 | addStatPoint(id, amount) { 306 | this.actor.addParam(id, amount); 307 | } 308 | } 309 | 310 | // Add new window type to the Window Manager 311 | Kru.helpers.windowHandlers['statuswindow'] = Kru_StatusWindow; 312 | 313 | 314 | /* 315 | * Replace Scene_Status 316 | */ 317 | Kru.AS.Scene_Status = Scene_Status; 318 | 319 | function Scene_Status() { 320 | this.initialize.apply(this, arguments); 321 | }; 322 | 323 | Scene_Status.prototype = Object.create(Scene_ItemBase.prototype); 324 | Scene_Status.prototype.constructor = Scene_Skill; 325 | 326 | Scene_Status.prototype.initialize = function() { 327 | Scene_ItemBase.prototype.initialize.call(this); 328 | }; 329 | 330 | Scene_Status.prototype.create = function() { 331 | Scene_ItemBase.prototype.create.call(this); 332 | 333 | this.wm = new Kru.helpers.WindowManager(this); 334 | 335 | // Top Window: stats 336 | let statusWin = this.wm.addWindow({ 337 | name: 'status', 338 | width: 1, 339 | height: 0.75, 340 | type: 'statuswindow' 341 | }); 342 | 343 | statusWin.activate(); 344 | 345 | // Bottom Window: skill details. 346 | let infoWindow = this.wm.addWindow({ 347 | name: 'info', 348 | width: 1, 349 | height: .25, 350 | type: 'help', 351 | content: '' 352 | }); 353 | 354 | statusWin.setHelpWindow(infoWindow); 355 | }; 356 | -------------------------------------------------------------------------------- /Kru_BattleMovementFrames.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Kru_ExtraMovementFramesPatch.js 3 | //============================================================================= 4 | 5 | /*: 6 | * @plugindesc Adds movement frames to battle enemies. A *much* simpler version 7 | * of Yanfly's AnimatedSVEnemies. 8 | * @author Krusynth 9 | * 10 | * @help 11 | * This plugin allows for very simple multiframe animations of enemies. Create 12 | * your sprite with frames horizontally. In the enemy tags, add a line listing 13 | * the number of frames, like so: 14 | * 15 | * You can set the order of the frames using a sequence tag: 16 | * 17 | * You can set the speed of the animation using a speed tag: The 18 | * default speed is 12; smaller is faster, bigger is slower. 19 | */ 20 | 21 | var Imported = Imported || {}; 22 | Imported.Kru_BMF = "1.0.0"; 23 | 24 | var Kru = Kru || {}; 25 | Kru.BMF = { 26 | }; 27 | 28 | if(!Imported.Kru_Core) { 29 | alert('Kru_PipeMinigame requires Kru_Core.'); 30 | throw new Error('Kru_PipeMinigame requires Kru_Core.'); 31 | } 32 | 33 | Kru.BMF.Sprite_Enemy___initialize = Sprite_Enemy.prototype.initialize; 34 | Sprite_Enemy.prototype.initialize = function(battler) { 35 | Kru.BMF.Sprite_Enemy___initialize.call(this, battler); 36 | 37 | this._motionCount = 0; 38 | this._pattern = 0; 39 | 40 | let meta = $dataEnemies[this._enemy._enemyId].meta; 41 | 42 | if(meta && meta.frames) { 43 | this._motion = Sprite_Actor.MOTIONS.walk; 44 | this._motion.frames = meta.frames; 45 | if(meta.sequence) { 46 | this._motion.sequence = meta.sequence.split(',').map(n => parseInt(n)); 47 | } 48 | if(meta.speed) { 49 | this._motion.speed = meta.speed; 50 | } 51 | } 52 | } 53 | 54 | Sprite_Enemy.prototype.update = function() { 55 | Sprite_Battler.prototype.update.call(this); 56 | if (this._enemy) { 57 | this.updateMotion(); 58 | this.updateEffect(); 59 | this.updateStateSprite(); 60 | } 61 | }; 62 | 63 | Sprite_Enemy.prototype.updateMotion = function() { 64 | this.updateMotionCount(); 65 | this.updateBitmap(); 66 | this.updateFrame(); 67 | } 68 | 69 | Sprite_Enemy.prototype.updateFrame = function() { 70 | Sprite_Battler.prototype.updateFrame.call(this); 71 | const bitmap = this.bitmap; 72 | if (bitmap) { 73 | const frames = this._motion.frames || 3; 74 | const motionIndex = this._motion ? this._motion.index : 0; 75 | 76 | const pattern = this._pattern < frames ? this._pattern : 1; 77 | let currentIndex = pattern; 78 | if(this._motion.sequence) { 79 | currentIndex = this._motion.sequence[pattern]; 80 | } 81 | 82 | const cw = bitmap.width / this._motion.frames; 83 | const ch = bitmap.height; 84 | const cx = Math.floor(motionIndex / 6) * 3 + currentIndex; 85 | const cy = motionIndex % 6; 86 | 87 | this.setFrame(cx * cw, cy * ch, cw, ch); 88 | } 89 | }; 90 | 91 | Sprite_Enemy.prototype.updateMotionCount = function() { 92 | if (this._motion && ++this._motionCount >= this.motionSpeed()) { 93 | if (this._motion.loop) { 94 | const frames = this._motion.frames || 4; 95 | this._pattern = (this._pattern + 1) % 4; 96 | } else if (this._pattern < 2) { 97 | this._pattern++; 98 | } else { 99 | this.refreshMotion(); 100 | } 101 | this._motionCount = 0; 102 | } 103 | }; 104 | 105 | Sprite_Enemy.prototype.motionSpeed = function() { 106 | return this._motion.speed || 12; 107 | }; -------------------------------------------------------------------------------- /Kru_Calendar.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Calendar 3 | // Version: 1.0.1 4 | //============================================================================= 5 | /*: 6 | * @plugindesc Calendar system 7 | * 8 | * @author Krusynth 9 | * 10 | * @help 11 | * ============================================================================ 12 | * Information 13 | * ============================================================================ 14 | * Creates a custom calendaring system, with month names etc. Can be paired with 15 | * SRD_GoldWindow_Customizer to show the month and day in the gold menu. 16 | * 17 | * This plugin also allows events to happen as the days pass. Make sure to call 18 | * KruPassDays(1) on rest/sleep/inn events to track the passage of time. 19 | * 20 | * Usage: 21 | * 22 | * KruShowDate(format, date) will display the current in-game date. Both 23 | * parameters are optional. 24 | * 25 | * Format: a string to specify a custom date format. Can include any of the 26 | * following special metacharacters: 27 | * 28 | * %M - the month 29 | * %d - the day 30 | * %Y - the year 31 | * %N - the total number of in-game days elapsed since the beginning of the game 32 | * 33 | * Defaults to the Format parameter. 34 | * 35 | * Date: a number representing the days since the beginning of the game. 36 | * Defaults to the Variable parameter. 37 | * 38 | * 39 | * KruPassDays(N) adds N days to the current day count (as specified in the 40 | * Variable parameter). 41 | * 42 | * 43 | * To add new events you can use KruAddUpcomingEvent and KruAddEvent: 44 | * 45 | * // Create an upcoming event to show a message one day from now. 46 | * KruAddUpcomingEvent('Day Two', 1, '$gameMessage.add("Day Two!")'); 47 | * 48 | * // Create a repeating event to show a message on the first day of the week. 49 | * KruAddEvent('Weekly Message', 1, '$gameMessage.add("Week!")', 'weekly'); 50 | * 51 | * // Create a repeating event that only happens three times. 52 | * KruAddEvent('Weekly Message', 1, '$gameMessage.add("Week!")', 'weekly', 3); 53 | * 54 | * 55 | * To check if the current day is a particular day, you can use the test 56 | * commands in your event conditionals. These return true or false if the today 57 | * matches the day in question. 58 | * 59 | * KruTestDay(12, 'Bloom') // Tests for a specific day of the month. 60 | * 61 | * KruTestMonth('Summer') // Tests just the month. 62 | * 63 | * KruTestYear(0) // Tests just the year. Note that the first year is year 0. 64 | * 65 | * @param Variable 66 | * @info Variable to use to store days that have passed. 67 | * @type variable 68 | * 69 | * @param Months 70 | * @info List of months. 71 | * @type struct[] 72 | * @default ["{\"Name\":\"Bloom\",\"Days\":\"90\"}","{\"Name\":\"Summer\",\"Days\":\"90\"}","{\"Name\":\"Harvest\",\"Days\":\"90\"}","{\"Name\":\"Winter\",\"Days\":\"90\"}"] 73 | * 74 | * @param OffsetDays 75 | * @text Start Days 76 | * @info Number of days of offset the start date. 77 | * @type number 78 | * @default 128 79 | * 80 | * @param OffsetYears 81 | * @text Start Year 82 | * @info Number of Years to offset the start date. 83 | * @type number 84 | * @default 320 85 | * 86 | * @param Format 87 | * @text Default Format 88 | * @info Use the following codes: %M (Month) %d (day) %Y (Year) %N (days count) 89 | * @type text 90 | * @default %M %d %Y 91 | * 92 | * @param NewDayMessage 93 | * @info Show the date each time KruPassDays() gets called. 94 | * @type boolean 95 | */ 96 | /*~struct~Month: 97 | * @param Name 98 | * @type text 99 | * 100 | * @param Days 101 | * @text Days in Month 102 | * @type number 103 | * @default false 104 | */ 105 | 106 | var Imported = Imported || {}; 107 | Imported.Kru_Calendar = "1.0.0"; 108 | 109 | var Kru = Kru || {}; 110 | Kru.Cal = {}; 111 | 112 | Kru.Cal.params = PluginManager.parameters('Kru_Calendar'); 113 | Kru.Cal.params.OffsetDays = parseInt(Kru.Cal.params.OffsetDays); 114 | Kru.Cal.params.OffsetYears = parseInt(Kru.Cal.params.OffsetYears); 115 | Kru.Cal.params.Variable = parseInt(Kru.Cal.params.Variable); 116 | Kru.Cal.params.DaysInYear = 0; 117 | Kru.Cal.params.Months = JSON.parse(Kru.Cal.params.Months); 118 | Kru.Cal.params.NewDayMessage = (Kru.Cal.params.NewDayMessage === "true"); 119 | 120 | for(let i = 0; i < Kru.Cal.params.Months.length; i++) { 121 | Kru.Cal.params.Months[i] = JSON.parse(Kru.Cal.params.Months[i]); 122 | Kru.Cal.params.DaysInYear += Kru.Cal.params.Months[i].Days; 123 | Kru.Cal.params.Months[i].Days = parseInt(Kru.Cal.params.Months[i].Days); 124 | } 125 | 126 | function KruShowDate(fmt, days) { 127 | let text = fmt || Kru.Cal.params['Format']; 128 | 129 | let date = Kru.Cal.getDate(days); 130 | 131 | text = text.replace('%Y', date.year) 132 | .replace('%M', date.month) 133 | .replace('%d', date.day) 134 | .replace('%N', date.days); 135 | 136 | return text; 137 | } 138 | 139 | Kru.Cal.getDate = function(days) { 140 | days = days || 141 | ($gameVariables._data[Kru.Cal.params.Variable] + Kru.Cal.params.OffsetDays); 142 | 143 | let date = {} 144 | date.days = days; 145 | 146 | date.year = Math.floor(days / Kru.Cal.params.DaysInYear) 147 | + Kru.Cal.params['OffsetYears']; 148 | 149 | let monthDay = Kru.Cal.dateToMonthDay(days); 150 | date.month = monthDay[0].Name; 151 | date.day = monthDay[1]; 152 | 153 | return date; 154 | } 155 | 156 | Kru.Cal.dateToMonthDay = function(days) { 157 | let day = days % Kru.Cal.params.DaysInYear; 158 | 159 | for(let i = 0; i < Kru.Cal.params.Months.length; i++) { 160 | month = Kru.Cal.params.Months[i]; 161 | 162 | if(day - month.Days < 0) { 163 | break; 164 | } 165 | else { 166 | day -= month.Days; 167 | } 168 | } 169 | 170 | return [month, day]; 171 | } 172 | 173 | function KruPassDays(days) { 174 | $gameVariables._data[Kru.Cal.params.Variable] += parseInt(days); 175 | 176 | $gameSystem.kruHandleEvents(); 177 | 178 | if(Kru.Cal.params.NewDayMessage) { 179 | $gameMessage.add(KruShowDate() + '\f'); 180 | } 181 | } 182 | 183 | /* Events system */ 184 | 185 | Kru.Cal.Game_System_initialize = Game_System.prototype.initialize; 186 | Game_System.prototype.initialize = function() { 187 | Kru.Cal.Game_System_initialize.call(this); 188 | 189 | this._kruEvents = this._kruEvents || {}; 190 | }; 191 | 192 | Game_System.prototype.kruHandleEvents = function() { 193 | let today = $gameVariables._data[Kru.Cal.params.Variable]; 194 | 195 | let names = Object.keys(this._kruEvents); 196 | 197 | let monthDay = Kru.Cal.dateToMonthDay(today); 198 | let month = monthDay[0]; 199 | let day = monthDay[1]; 200 | 201 | for(let i = 0; i < names.length; i++) { 202 | let name = names[i]; 203 | let event = this._kruEvents[name]; 204 | if( 205 | (event.repeat == 'yearly' && 206 | today % $gameVariables._data[Kru.Cal.params.DaysInYear] === event.date) || 207 | (event.repeat == 'monthly' && 208 | day === event.date) || 209 | (event.repeat == 'weekly' && 210 | today % 7 === event.date) || 211 | (event.repeat == 'daily') || 212 | (!event.repeat && event.date <= today) 213 | 214 | ) { 215 | eval(event.script); 216 | 217 | // If we're only repeating a set number of times. 218 | if(event.times) { 219 | this._kruEvents[name].times--; 220 | } 221 | if(event.times === 0) { 222 | delete this._kruEvents[name]; 223 | } 224 | } 225 | 226 | } 227 | } 228 | 229 | Game_System.prototype.addEvent = function(name, event) { 230 | this._kruEvents[name] = event; 231 | } 232 | 233 | Game_System.prototype.removeEvent = function(name) { 234 | delete this._kruEvents[name]; 235 | } 236 | 237 | function KruAddEvent(name, date, script, repeat, times) { 238 | if(!repeat && !times) { 239 | times = 1; 240 | } 241 | $gameSystem.addEvent(name, { 242 | date: date, 243 | script: script, 244 | repeat: repeat, 245 | times: times 246 | }); 247 | } 248 | 249 | function KruAddUpcomingEvent(name, daysFromNow, script) { 250 | let date = $gameVariables._data[Kru.Cal.params.Variable] + daysFromNow; 251 | KruAddEvent(name, date, script); 252 | } 253 | 254 | function KruRemoveEvent(name) { 255 | $gameSystem.removeEvent(name); 256 | } 257 | 258 | // Day test conditional helpers 259 | 260 | // Tests for a specific day of the month. 261 | function KruTestDay(day, month) { 262 | let date = Kru.Cal.getDate(); 263 | return (date.day == day && date.month == month); 264 | } 265 | 266 | // Tests just the month. 267 | function KruTestMonth(month) { 268 | let date = Kru.Cal.getDate(); 269 | return (date.month == month); 270 | } 271 | 272 | // Tests just the year. 273 | function KruTestYear(year) { 274 | let date = Kru.Cal.getDate(); 275 | return (date.year == year); 276 | } 277 | 278 | -------------------------------------------------------------------------------- /Kru_ClassChange.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Class Change 3 | // Version: 1.0.0 4 | //============================================================================= 5 | /*: 6 | * @plugindesc v1.0.0 Allows for class change on level up and stat increases. 7 | * 8 | * @author Krusynth 9 | * 10 | * @help 11 | * ============================================================================ 12 | * Information 13 | * ============================================================================ 14 | * 15 | * This plugin allows players to automatically change class when particular 16 | * requirements are met. 17 | * 18 | * This plugin seamlessly interacts with Kru_AssignStats. 19 | * 20 | * Usage 21 | * Add a line to the class' notes field with a JSON object in the following 22 | * format: 23 | * {"req":{"level":10,"class":"Fighter","attr":{"atk":25,"def":15}}} 24 | * 25 | * In this example, the class change will happen on level up when the player is 26 | * at least level 10, currently has the Fighter class, and has a minimum Attack 27 | * attribute of 25 and Defense of 15. 28 | * 29 | * Terms & Conditions 30 | * This plugin is free for non-commercial and commercial use. 31 | */ 32 | 33 | /* 34 | * TODO: remap RPG Maker MV math to use the new stats. 35 | */ 36 | 37 | var Imported = Imported || {}; 38 | Imported.Kru_ClassChange = "1.0.0"; 39 | 40 | var Kru = Kru || {}; 41 | Kru.CC = { 42 | config: {} 43 | }; 44 | 45 | if(!Imported.Kru_Core) { 46 | alert("Kru_StatOverhaul requires Kru_Core."); 47 | throw new Error("Kru_StatOverhaul requires Kru_Core."); 48 | } 49 | 50 | /* 51 | * Setup our classes to upgrade automatically. 52 | */ 53 | Kru.CC.DataManager_isDatabaseLoaded = DataManager.isDatabaseLoaded; 54 | DataManager.isDatabaseLoaded = function() { 55 | Kru.CC.DataManager_isDatabaseLoaded.call(this); 56 | Kru.helpers.processNotes('classes'); 57 | return true; 58 | }; 59 | 60 | // Level up 61 | Kru.CC.Game_Actor_levelUp = Game_Actor.prototype.levelUp; 62 | Game_Actor.prototype.levelUp = function () { 63 | Kru.CC.Game_Actor_levelUp.call(this); 64 | 65 | // After our level up, check if we should change class. 66 | this.checkClassChange(); 67 | }; 68 | 69 | /* 70 | * If we're using the assign stats plugin, do class change on stat change. 71 | */ 72 | if(Imported.Kru_AssignStats) { 73 | Kru.CC.Kru_StatusWindow__onOk = Kru_StatusWindow.prototype.onOk; 74 | Kru_StatusWindow.prototype.onOk = function() { 75 | Kru.CC.Kru_StatusWindow__onOk.call(this); 76 | 77 | // After we've updated our attributes, check to see if we need to change class. 78 | this.checkClassChange(); 79 | } 80 | } 81 | 82 | Kru_StatusWindow.prototype.checkClassChange = function() { 83 | var currentClass = $dataClasses[this.actor._classId]; 84 | 85 | classCheck: for(hCC_i = 0; hCC_i < $dataClasses.length; hCC_i++) { 86 | if(hCC_i != this.actor._classId) { 87 | var cls = $dataClasses[hCC_i]; 88 | 89 | if(typeof(cls) === 'undefined' || cls === null || typeof(cls._notes) === 'undefined') { 90 | continue classCheck; 91 | } 92 | 93 | // All class changes have requirements. 94 | if(cls._notes.req) { 95 | 96 | // Level Check 97 | if(cls._notes.req.level && this.actor._level < cls._notes.req.level) { 98 | continue classCheck; 99 | } 100 | 101 | // Previous Class Check 102 | if(typeof(cls._notes.req.class) !== 'undefined') { 103 | if(Array.isArray(cls._notes.req.class) && cls._notes.req.class.indexOf(currentClass.name) === -1){ 104 | continue classCheck; 105 | } 106 | if(typeof(cls._notes.req.class) === 'string' && cls._notes.req.class !== currentClass.name) { 107 | continue classCheck; 108 | } 109 | } 110 | 111 | // Attribute Requirements Check 112 | if(cls._notes.req.attr) { 113 | var keys = Object.keys(cls._notes.req.attr); 114 | for(hCC_k = 0; hCC_k < keys.length; hCC_k++) { 115 | var key = keys[hCC_k]; 116 | var value = cls._notes.req.attr[key]; 117 | if(value < 0) { 118 | if(this.actor[key] > (0-value)) { 119 | continue classCheck; 120 | } 121 | } 122 | else { 123 | if(this.actor[key] < value) { 124 | continue classCheck; 125 | } 126 | } 127 | } 128 | } 129 | 130 | // If we have passed all other requirement checks, change class. 131 | this.doClassChange(cls); 132 | 133 | // Only change class once. 134 | break; 135 | } 136 | 137 | } 138 | } 139 | } 140 | 141 | Kru_StatusWindow.prototype.doClassChange = function(cls) { 142 | this.actor._classId = cls.id; 143 | this.refresh(); 144 | 145 | var msg = this.actor.name() + ' has become a ' + cls.name; 146 | 147 | // Play a sound and show a message. 148 | $gameMessage.add(msg); 149 | 150 | // TODO: make this customizable. 151 | // AudioManager.playMe($gameSystem.victoryMe()); 152 | 153 | var msgWindow = new Window_Message(); 154 | var newWin = this._win.scene.addWindow(msgWindow); 155 | 156 | setTimeout(function(msgWindow) { 157 | $gameMessage.clear(); 158 | this._win.scene.removeChild(msgWindow); 159 | msgWindow.visible = false; 160 | 161 | }.bind(this, msgWindow), 3000); 162 | 163 | }; 164 | -------------------------------------------------------------------------------- /Kru_ClearMapPhotos.js: -------------------------------------------------------------------------------- 1 | /*: 2 | * Clear Map Photos 3 | * 4 | * @plugindesc 1.0 Clear Map Photos - Remove photos from the map on load. 5 | * 6 | * @author Krusynth 7 | * 8 | * @help 9 | * This plugin automatically clears all previously-loaded pictures when a map is 10 | * loaded. This makes it easy to automatically unload pictures for parallax 11 | * maps. 12 | * 13 | * Terms & Conditions 14 | * This plugin is MIT Licensed. (Free for non-commercial and commercial use.) 15 | */ 16 | 17 | var Imported = Imported || {}; 18 | Imported.Kru_ClearMapPhotos = 1.0; 19 | 20 | (function() { 21 | "use strict"; 22 | 23 | var _originalMapLoadedCallback = Scene_Map.prototype.onMapLoaded; 24 | 25 | Scene_Map.prototype.onMapLoaded = function() { 26 | $gameScreen.clearPictures(); 27 | _originalMapLoadedCallback.call(this); 28 | 29 | } 30 | 31 | })(); -------------------------------------------------------------------------------- /Kru_Core.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Kru Core 3 | // Version: 1.0.2 4 | //============================================================================= 5 | /*: 6 | * @plugindesc Shared base for many Krusynth plugins 7 | * 8 | * @author Krusynth 9 | * 10 | * @param ---General--- 11 | * @default 12 | * 13 | * @help 14 | * ============================================================================ 15 | * Information 16 | * ============================================================================ 17 | * 18 | * This is the base include for many Krusynth RPG Maker MV plugins. It includes 19 | * a JSON loader and window manager. 20 | */ 21 | 22 | var Imported = Imported || {}; 23 | Imported.Kru_Core = "1.0.2"; 24 | 25 | var Kru = Kru || {}; 26 | Kru.Core = { 27 | config: {} 28 | }; 29 | 30 | Kru.Parameters = PluginManager.parameters('Kru_Core'); 31 | 32 | 33 | /*** Helpers ***/ 34 | if(!Kru.helpers) { 35 | Kru.helpers = { 36 | _events: {} 37 | }; 38 | } 39 | 40 | Kru.helpers.getMapData = function(mapId, callback) { 41 | let filename = 'Map%1.json'.format(mapId.padZero(3)); 42 | return this.getFileData(filename, callback); 43 | }; 44 | 45 | // Gets data from a JSON file. 46 | // Unlike the original version, this is synchronous and returns the result. 47 | Kru.helpers.getFileData = function(src, callback) { 48 | let data; 49 | 50 | let xhr = new XMLHttpRequest(); 51 | let url = 'data/' + src; 52 | xhr.open('GET', url, false); 53 | xhr.overrideMimeType('application/json'); 54 | xhr.onload = function() { 55 | if(xhr.status < 400) { 56 | data = JSON.parse(xhr.responseText); 57 | DataManager.extractMetadata(data); 58 | 59 | if(typeof(callback) !== 'undefined') { 60 | callback(data); 61 | } 62 | } 63 | }; 64 | xhr.onerror = function() { 65 | DataManager._errorUrl = DataManager._errorUrl || url; 66 | }; 67 | xhr.send(); 68 | 69 | return data; 70 | }; 71 | 72 | /* TODO: Convert all usage of parseNoteTags into DataManager.extractMetadata */ 73 | 74 | // Override loadDataFile so we get the name of our object in onLoad. 75 | DataManager.loadDataFile = function(name, src) { 76 | var xhr = new XMLHttpRequest(); 77 | var url = 'data/' + src; 78 | xhr.open('GET', url); 79 | xhr.overrideMimeType('application/json'); 80 | xhr.onload = function() { 81 | if (xhr.status < 400) { 82 | window[name] = JSON.parse(xhr.responseText); 83 | DataManager.onLoad(window[name], name); 84 | } 85 | }; 86 | xhr.onerror = function() { 87 | DataManager._errorUrl = DataManager._errorUrl || url; 88 | }; 89 | window[name] = null; 90 | xhr.send(); 91 | }; 92 | 93 | // Modify onLoad to callback any events. 94 | Kru.helpers.DataManager_onLoad = DataManager.onLoad; 95 | DataManager.onLoad = function(object, name) { 96 | Kru.helpers.DataManager_onLoad.call(this, object); 97 | Kru.helpers.eventCallback(name, object) 98 | } 99 | 100 | Kru.helpers.addEvent = function(name, fn) { 101 | if(typeof Kru.helpers._events[name] == 'undefined') { 102 | Kru.helpers._events[name] = []; 103 | } 104 | Kru.helpers._events[name].push(fn); 105 | } 106 | 107 | Kru.helpers.eventCallback = function(name, object) { 108 | if(typeof Kru.helpers._events[name] !== 'undefined' && 109 | Array.isArray(Kru.helpers._events[name])) { 110 | for(let i = 0; i < Kru.helpers._events[name].length; i++) { 111 | Kru.helpers._events[name][i](object, name); 112 | } 113 | } 114 | } 115 | 116 | Kru.helpers.DataManager_extractMetadata = DataManager.extractMetadata 117 | DataManager.extractMetadata = function(data) { 118 | let note = data.note; 119 | let tmp = note; 120 | if(typeof data.meta == 'undefined') { 121 | data.meta = {}; 122 | } 123 | // First pass: tags. 124 | let re = /<([^<>:]+)(:?)([^>]*)>/gm; 125 | while(true) { 126 | let match = re.exec(tmp); 127 | if (match) { 128 | if (match[2] === ':') { 129 | data.meta[match[1]] = match[3]; 130 | } else { 131 | data.meta[match[1]] = true; 132 | } 133 | note = note.replace(match[0], ''); 134 | } else { 135 | break; 136 | } 137 | } 138 | 139 | // Second pass: assume single-line JSON elements. 140 | let notes = note.split(/\r?\n/); 141 | for(let i = 0; i < notes.length; i++) { 142 | try { 143 | let tmpData = JSON.parse(notes[i]); 144 | Object.assign(data.meta, tmpData); 145 | } catch(e) {}; 146 | } 147 | 148 | 149 | } 150 | 151 | // Parse tags into an object 152 | // TODO: fold into extractMetadata; 153 | Kru.helpers.parseNoteTags = function(note) { 154 | if(typeof(note) == 'string' && note.length > 0) { 155 | let data = {}; 156 | 157 | // If we have JSON, use that. 158 | let notes = note.split(/\r?\n/); 159 | for(let pNT = 0; pNT < notes.length; pNT++) { 160 | try { 161 | let tmpData = JSON.parse(notes[pNT]); 162 | Object.assign(data, tmpData); 163 | } catch(e) {}; 164 | } 165 | if(Object.keys(data).length > 0) { 166 | return data; 167 | } 168 | 169 | // Otherwise we have to parse some tags. 170 | let regex = /<([A-Za-z0-9-_]+) ?(.*?)>/g; 171 | let result = {}; 172 | while(m = regex.exec(note)) { 173 | let name = m[1]; 174 | 175 | // If we have multiple arguments, create a list. 176 | let value = m[2].split(' '); 177 | if(value.length > 1) { 178 | // If we have an assignment, we have a hash map. 179 | if(value[0].split('=').length > 1) { 180 | let values = {}; 181 | for(let j = 0; j < value.length; j++) { 182 | let valObj = value[j].split('='); 183 | values[valObj[0]] = Kru.helpers.normalizeValues(valObj[1]); 184 | } 185 | } 186 | // Otherwise we have a list of values 187 | else { 188 | values = []; 189 | for(let j = 0; j < value.length; j++) { 190 | values.push(Kru.helpers.normalizeValues(value[j])); 191 | } 192 | } 193 | 194 | value = values; 195 | } 196 | else { 197 | value = Kru.helpers.normalizeValues(value[0]); 198 | } 199 | 200 | result[name] = value; 201 | } 202 | return result; 203 | } 204 | else return {}; 205 | }; 206 | 207 | Kru.helpers.normalizeValues = function(value) { 208 | if(value.match(/^[0-9]+$/)) { 209 | value = Number(value); 210 | } 211 | return value; 212 | }; 213 | 214 | // Parse notes 215 | 216 | Kru.helpers.processNotes = function(type) { 217 | if(type === 'skills') { 218 | // Only process once. 219 | if(typeof($dataSkills._kru_processed) === 'undefined') { 220 | for(let i = 0; i < $dataSkills.length; i++) { 221 | if($dataSkills[i]) { 222 | $dataSkills[i]._notes = Kru.helpers.parseNoteTags($dataSkills[i].note); 223 | } 224 | } 225 | $dataSkills._kru_processed = true; 226 | } 227 | } 228 | else if(type === 'classes') { 229 | // Only process once. 230 | if(typeof($dataClasses._kru_processed) === 'undefined') { 231 | for(let i = 0; i < $dataClasses.length; i++) { 232 | if($dataClasses[i]) { 233 | $dataClasses[i]._notes = Kru.helpers.parseNoteTags($dataClasses[i].note); 234 | } 235 | } 236 | $dataClasses._kru_processed = true; 237 | } 238 | } 239 | }; 240 | 241 | 242 | /* 243 | * Kru WindowManager – the easy way to manage scene windows. 244 | */ 245 | 246 | Kru.helpers.WindowManager = function (scene) { 247 | this.scene = scene; 248 | 249 | this.last = { 250 | _x: 0, 251 | _y: 0, 252 | _w: 0, 253 | _h: 0 254 | }; 255 | this.windows = {}; 256 | 257 | this.addWindow = function(options) { 258 | options._w = options._w || Graphics.boxWidth * options.width; 259 | options._h = options._h || Graphics.boxHeight * options.height; 260 | 261 | // By default, put this next to the previous item. 262 | if(typeof(options._x) == 'undefined' && typeof(options._y) == 'undefined') { 263 | options._x = this.last._x + this.last._w; 264 | options._y = this.last._y; 265 | 266 | // If this won't fit next to the previous item, move it to the next row. 267 | if(options._x + options._w > Graphics.boxWidth) { 268 | options._x = 0; 269 | options._y = this.last._y + this.last._h; 270 | } 271 | } 272 | 273 | options.scene = this.scene; 274 | options.actor = this.scene.actor(); 275 | options.manager = this; 276 | 277 | let type = options.type || 'default'; 278 | 279 | let win = new Kru.helpers.windowHandlers[type](options); 280 | 281 | win.open(); 282 | win.show(); 283 | 284 | let key = win.name || Object.keys(this.windows).length; 285 | 286 | this.windows[key] = win; 287 | this.last = win; 288 | 289 | this.scene.addWindow(win); 290 | 291 | return win; 292 | } 293 | 294 | return this; 295 | } 296 | 297 | Kru.helpers.windowHandlers = { 298 | default: Kru_GenericWindow, 299 | basic: Kru_GenericWindow, 300 | list: Kru_GenericListWindow, 301 | customlist: Kru_CustomListWindow, 302 | help: Kru_GenericHelpWindow 303 | }; 304 | 305 | Kru.helpers.WindowManager.prototype.text = function() {}; 306 | 307 | /* 308 | * Window mixin 309 | */ 310 | 311 | function Kru_WindowMixin() { 312 | this._iconSet = this._iconSet || 'IconSet'; 313 | this._iconWidth = Window_Base._iconWidth; 314 | this._iconHeight = Window_Base._iconHeight; 315 | this._lineHeight = 36; 316 | this._handlers = {}; 317 | 318 | this.iconInit = function(win) { 319 | if(win.icon) { 320 | if(win.icon.height) { 321 | this._iconHeight = win.icon.height; 322 | } 323 | if(win.icon.width) { 324 | this._iconWidth = win.icon.width; 325 | } 326 | if(win.icon.set) { 327 | this._iconSet = win.icon.set; 328 | } 329 | } 330 | if(typeof win.lineHeight !== 'undefined') { 331 | this._lineHeight = win.lineHeight; 332 | } 333 | }; 334 | 335 | this.loadIcons = function(name) { 336 | name = name || this._iconSet; 337 | 338 | if(!this.bitmap) { 339 | this.bitmap = ImageManager.loadSystem(name); 340 | let wait = true; 341 | return new Promise(resolve => { 342 | this.bitmap.addLoadListener(() => { 343 | resolve(); 344 | }); 345 | }); 346 | } 347 | }; 348 | 349 | this.drawIcon = async function(iconIndex, x, y, set) { 350 | if(!this.bitmap) { 351 | if(!set) { 352 | set = this._iconSet; 353 | } 354 | await this.loadIcons(set); 355 | } 356 | 357 | let cols = Math.round(this.bitmap.width / this._iconWidth); 358 | let pw = this._iconWidth; 359 | let ph = this._iconHeight; 360 | let sx = iconIndex % cols * pw; 361 | let sy = Math.floor(iconIndex / cols) * ph; 362 | 363 | this.contents.blt(this.bitmap, sx, sy, pw, ph, x, y); 364 | }; 365 | 366 | // We use a modified drawIcon which doesn't need to wait for the image to be loaded. 367 | // In this instance you'll need to call loadIcons manually. 368 | this.drawIconIndex = async function(idx, idy, x, y, rotate) { 369 | await this.loadIcons(); 370 | 371 | let sx = idx * this._iconWidth; 372 | let sy = idy * this._iconHeight; 373 | 374 | if(rotate) { 375 | this.contents.bltRotate(this.bitmap, sx, sy, this._iconWidth, this._iconHeight, x, y, rotate); 376 | } 377 | else { 378 | this.contents.blt(this.bitmap, sx, sy, this._iconWidth, this._iconHeight, x, y); 379 | } 380 | } 381 | 382 | this.drawItemName = function(item, x, y, width) { 383 | width = width || 312; 384 | if (item) { 385 | let iconBoxWidth = this._iconWidth + 4; 386 | this.resetTextColor(); 387 | this.drawIcon(item.iconIndex, x + 2, y + 2); 388 | this.drawText(item.name, x + iconBoxWidth, y, width - iconBoxWidth); 389 | } 390 | }; 391 | 392 | this.lineHeight = function() { 393 | return this._lineHeight; 394 | }; 395 | 396 | Object.defineProperty(this, '_x', { get: function () { return this._win._x } }); 397 | Object.defineProperty(this, '_y', { get: function () { return this._win._y } }); 398 | Object.defineProperty(this, '_w', { get: function () { return this._win._w } }); 399 | Object.defineProperty(this, '_h', { get: function () { return this._win._h } }); 400 | 401 | return this; 402 | } 403 | 404 | 405 | /* 406 | * Override the Base window to take an object with all of the properties we need. 407 | */ 408 | 409 | function Kru_GenericWindow() { 410 | this.initialize.apply(this, arguments); 411 | } 412 | 413 | Kru_GenericWindow.prototype = Object.create(Window_Base.prototype); 414 | Kru_GenericWindow.prototype.constructor = Window_Base; 415 | 416 | Kru_GenericWindow.prototype.initialize = function(win) { 417 | this._win = win; 418 | 419 | Window_Base.prototype.initialize.call(this, win._x, win._y, win._w, win._h); 420 | if(win.content) { 421 | this.drawText(win.content, 0, 0, win._w); 422 | } 423 | 424 | this.iconInit(win); 425 | } 426 | 427 | Kru_WindowMixin.call(Kru_GenericWindow.prototype); 428 | 429 | /* 430 | * Override the Selectable window to expect a list. 431 | */ 432 | function Kru_GenericListWindow() { 433 | this.initialize.apply(this, arguments); 434 | } 435 | 436 | Kru_GenericListWindow.prototype = Object.create(Window_Selectable.prototype); 437 | Kru_GenericListWindow.prototype.constructor = Window_Selectable; 438 | 439 | Kru_GenericListWindow.prototype.initialize = function(win) { 440 | this._win = win; 441 | if(win.content) { 442 | this._data = win.content; 443 | } 444 | 445 | if(this._data && this._data.length) { 446 | this._index = 0; 447 | } 448 | 449 | this.iconInit(win); 450 | 451 | Object.defineProperty(this, 'current', { get: function() { return this._data[this._index]; }}); 452 | 453 | Window_Selectable.prototype.initialize.call(this, win._x, win._y, win._w, win._h); 454 | this.refresh(); 455 | }; 456 | 457 | Kru_GenericListWindow.prototype.maxItems = function() { 458 | if(this._data && this._data.length) { 459 | return this._data.length; 460 | } 461 | else { 462 | return 0; 463 | } 464 | }; 465 | 466 | Kru_GenericListWindow.prototype.drawItem = function(index) { 467 | let content = this._data[index]; 468 | let yOffset = this.lineHeight() * index; 469 | 470 | if(typeof content === 'object') { 471 | this.drawItemName(content, 0, yOffset, this._win._w); 472 | } 473 | else { 474 | this.drawText(content, 0, yOffset, this._win._w); 475 | } 476 | }; 477 | 478 | Kru_GenericListWindow.prototype.updateHelp = function() { 479 | this.setHelpWindowItem(this.item()); 480 | }; 481 | 482 | // Stolen from Window_ItemList. 483 | Kru_GenericListWindow.prototype.item = function() { 484 | let index = this.index(); 485 | return this._data && index >= 0 ? this._data[index] : null; 486 | }; 487 | 488 | Kru_WindowMixin.call(Kru_GenericListWindow.prototype); 489 | 490 | /* 491 | * Override the Help window to not put it at the top of the screen. 492 | */ 493 | function Kru_GenericHelpWindow() { 494 | this.initialize.apply(this, arguments); 495 | } 496 | 497 | Kru_GenericHelpWindow.prototype = Object.create(Window_Help.prototype); 498 | Kru_GenericHelpWindow.prototype.constructor = Window_Help; 499 | 500 | Kru_GenericHelpWindow.prototype.initialize = function(win) { 501 | this._win = win; 502 | 503 | this.iconInit(win); 504 | 505 | Window_Base.prototype.initialize.call(this, win._x, win._y, win._w, win._h); 506 | this._text = ''; 507 | }; 508 | 509 | Kru_GenericHelpWindow.prototype.drawTextExOrig = Window_Base.prototype.drawTextEx; 510 | Kru_GenericHelpWindow.prototype.drawTextEx = function(text, x, y) { 511 | 512 | //One character width 513 | let charW = this.textWidth('X'); 514 | let width = this._win._w - (2 * this.textPadding()); 515 | let charsPerLine = Math.floor(width / charW); 516 | 517 | let newText = ''; 518 | // TODO: break on spaces instead of just line width. 519 | // TODO: fix spaces at the beginning of a line. 520 | for(let i = 0; i < text.length; i += (charsPerLine - 2)) { 521 | newText += text.substring(i, i+(charsPerLine - 2)) + "\n"; 522 | } 523 | 524 | this.drawTextExOrig(newText, x, y); 525 | } 526 | 527 | Kru_WindowMixin.call(Kru_GenericHelpWindow.prototype); 528 | 529 | /* 530 | * Create a list window where items can be placed arbitrarily. 531 | */ 532 | 533 | function Kru_CustomListWindow() { 534 | this.initialize.apply(this, arguments); 535 | }; 536 | 537 | Kru_CustomListWindow.prototype = Object.create(Kru_GenericListWindow.prototype); 538 | 539 | Kru_CustomListWindow.prototype.initialize = function(win) { 540 | this.lines = []; 541 | 542 | if(typeof(win.actor) != 'undefined') { 543 | this.actor = win.actor; 544 | } 545 | 546 | Kru_GenericListWindow.prototype.initialize.call(this, win); 547 | 548 | this._data = win.content || []; 549 | this.lines = win.lines || []; 550 | 551 | if(this._data && this._data.length) { 552 | this._index = 0; 553 | } 554 | 555 | // TODO: Are these values already stored somewhere? 556 | this.margin = 3; // Standard margin for selections. this.padding is too big? 557 | this.itemheight = 42; 558 | this.iconWidth = 42; // this._iconWidth is too short? 559 | this.fontWidth = 14; 560 | 561 | // Set event handlers. 562 | this.setHandler('ok', this.onOk.bind(this)); 563 | this.setHandler('cancel', this.onCancel.bind(this)); 564 | 565 | this.refresh(); 566 | }; 567 | 568 | Kru_CustomListWindow.prototype.onOk = function() { 569 | this.refresh(); 570 | this.activate(); 571 | }; 572 | 573 | Kru_CustomListWindow.prototype.onCancel = function() { 574 | this._win.scene.popScene(); 575 | }; 576 | 577 | Kru_CustomListWindow.prototype.failState = function() { 578 | SoundManager.playBuzzer(); 579 | this.activate(); 580 | }; 581 | 582 | Kru_CustomListWindow.prototype.refresh = function() { 583 | if (this.contents) { 584 | this.contents.clear(); 585 | } 586 | this.drawHeader(); 587 | this.drawAllLines(); 588 | this.drawAllItems(); 589 | this.drawFooter(); 590 | }; 591 | 592 | Kru_CustomListWindow.prototype.drawTitle = function() {}; 593 | Kru_CustomListWindow.prototype.drawFooter = function() {}; 594 | 595 | Kru_CustomListWindow.prototype.drawAllLines = function() { 596 | if(this.lines && this.lines.length > 0) { 597 | for (let i = 0; i < this.lines.length; i++) { 598 | this.drawLine(this.lines[i]); 599 | } 600 | } 601 | }; 602 | 603 | Kru_CustomListWindow.prototype.drawLine = function(line) { 604 | let color = '#ffffff'; 605 | if(typeof(line.color) != 'undefined') { 606 | color = line.color; 607 | } 608 | 609 | let width = 2; 610 | if(typeof(line.width) != 'undefined') { 611 | width = line.width; 612 | } 613 | 614 | this.contents.kDrawLine( 615 | Math.ceil(line.location[0]), 616 | Math.ceil(line.location[1]), 617 | Math.ceil(line.location[2]), 618 | Math.ceil(line.location[3]), 619 | color, width); 620 | }; 621 | 622 | Kru_CustomListWindow.prototype.drawItem = function(index) { 623 | let content = this._data[index]; 624 | 625 | if(typeof content === 'object') { 626 | this.drawItemName(content, content.location[0], content.location[1], this._win._w); 627 | } 628 | else { 629 | this.drawText(content, content.location[0], content.location[1], this._win._w); 630 | } 631 | }; 632 | 633 | Kru_CustomListWindow.prototype.drawItemName = function(item, x, y, width) { 634 | width = width || 312; 635 | if (item) { 636 | let iconBoxWidth = Window_Base._iconWidth + 4; 637 | if(item.disabled) { 638 | this.changeTextColor(this.textColor(7)); 639 | } 640 | else { 641 | this.changeTextColor(this.normalColor()); 642 | } 643 | 644 | let x2 = x; 645 | if(typeof(item.iconIndex) != 'undefined') { 646 | this.drawIcon(item.iconIndex, x + 2, y + 2); 647 | x2 += iconBoxWidth; 648 | width -= iconBoxWidth; 649 | } 650 | this.drawText(item.name, x2, y, width); 651 | this.changeTextColor(this.normalColor()); 652 | } 653 | }; 654 | 655 | Kru_CustomListWindow.prototype.updateCursor = function() { 656 | if (this._cursorAll) { 657 | let allRowsHeight = this.maxRows() * this.itemHeight(); 658 | this.setCursorRect(0, 0, this.contents.width, allRowsHeight); 659 | this.setTopRow(0); 660 | } else if (this.isCursorVisible()) { 661 | let rect = this.itemRect(this.index()); 662 | if(rect) { 663 | this.setCursorRect( 664 | rect.x - rect.margin, rect.y - rect.margin, rect.width, rect.height); 665 | } 666 | } else { 667 | this.setCursorRect(0, 0, 0, 0); 668 | } 669 | }; 670 | 671 | // Reimplement the navigation commands for the tree. 672 | Kru_CustomListWindow.prototype.itemRect = function(index) { 673 | let rect = new Rectangle(); 674 | if(typeof(this._data) === 'undefined' || 675 | typeof(this._data[index]) === 'undefined') { 676 | return; 677 | } 678 | let content = this._data[index]; 679 | 680 | rect.x = content.location[0]; 681 | rect.y = content.location[1]; 682 | 683 | rect.width = 0; // this.itemWidth(); 684 | if(typeof(content.width) != 'undefined') { 685 | rect.width = content.width; 686 | } 687 | else { 688 | if(content.iconIndex) { 689 | rect.width += this.iconWidth; 690 | } 691 | rect.width += (content.name.length * this.fontWidth); 692 | } 693 | 694 | rect.height = this.itemheight;// this.itemHeight(); 695 | if(typeof(content.height) != 'undefined') { 696 | rect.height = content.height; 697 | } 698 | 699 | rect.margin = this.margin; 700 | 701 | if(typeof(content.margin) != 'undefined') { 702 | rect.margin = content.margin 703 | } 704 | 705 | return rect; 706 | }; 707 | 708 | /* TODO 709 | itemWidth 710 | itemHeight 711 | 712 | Kru_CustomListWindow.prototype.cursorDown = function(wrap) { 713 | var index = this.index(); 714 | var maxItems = this.maxItems(); 715 | var maxCols = this.maxCols(); 716 | if (index < maxItems - maxCols || (wrap && maxCols === 1)) { 717 | this.select((index + maxCols) % maxItems); 718 | } 719 | }; 720 | 721 | Kru_CustomListWindow.prototype.cursorUp = function(wrap) { 722 | var index = this.index(); 723 | var maxItems = this.maxItems(); 724 | var maxCols = this.maxCols(); 725 | if (index >= maxCols || (wrap && maxCols === 1)) { 726 | this.select((index - maxCols + maxItems) % maxItems); 727 | } 728 | }; 729 | 730 | Kru_CustomListWindow.prototype.cursorRight = function(wrap) { 731 | var index = this.index(); 732 | var maxItems = this.maxItems(); 733 | var maxCols = this.maxCols(); 734 | if (maxCols >= 2 && (index < maxItems - 1 || (wrap && this.isHorizontal()))) { 735 | this.select((index + 1) % maxItems); 736 | } 737 | }; 738 | 739 | Kru_CustomListWindow.prototype.cursorLeft = function(wrap) { 740 | var index = this.index(); 741 | var maxItems = this.maxItems(); 742 | var maxCols = this.maxCols(); 743 | if (maxCols >= 2 && (index > 0 || (wrap && this.isHorizontal()))) { 744 | this.select((index - 1 + maxItems) % maxItems); 745 | } 746 | }; 747 | */ 748 | 749 | 750 | 751 | /* 752 | * Add a drawLine function to our Bitmap object. Useful for our tree windows. 753 | */ 754 | 755 | Bitmap.prototype.kDrawLine = function(x1, y1, x2, y2, color, width) { 756 | if(!color) { 757 | color = '#ffffff'; 758 | } 759 | if(!width) { 760 | width = 1; 761 | } 762 | let context = this._context; 763 | context.save(); 764 | context.strokeStyle = color; 765 | context.lineWidth = width; 766 | context.beginPath(); 767 | context.moveTo(x1,y1); 768 | context.lineTo(x2,y2); 769 | context.stroke(); 770 | context.restore(); 771 | this._setDirty(); 772 | }; 773 | 774 | Bitmap.prototype.kDrawPolygon = function(points, line, fill) { 775 | let context = this._context; 776 | context.save(); 777 | 778 | if(typeof(line.width) != 'undefined') { 779 | context.lineWidth = line.width; 780 | } 781 | if(typeof(line.color) != 'undefined') { 782 | context.strokeStyle = line.color; 783 | } 784 | if(typeof(fill.color) != 'undefined') { 785 | context.fillStyle = fill.color; 786 | } 787 | if(typeof(fill.alpha) != 'undefined') { 788 | context.globalAlpha = fill.alpha; 789 | } 790 | context.beginPath(); 791 | 792 | context.moveTo(points[0][0], points[0][1]); 793 | 794 | for(let i = 1; i < points.length; i++) { 795 | context.lineTo(points[i][0], points[i][1]); 796 | } 797 | 798 | 799 | context.closePath(); 800 | 801 | if(typeof(fill) != 'undefined') { 802 | context.fill(); 803 | } 804 | 805 | context.globalAlpha = 1; 806 | } 807 | 808 | /* 809 | * Add rotation to Bitmap. 810 | * Original: https://forums.rpgmakerweb.com/index.php?threads/how-to-rotate-bitmap.48225/#post-502863 811 | */ 812 | 813 | if(!Bitmap.prototype.bltRotate) { 814 | Bitmap.prototype.bltRotate = function(source, sx, sy, sw, sh, dx, dy, angle, dw, dh) { 815 | angle = angle || 0; 816 | dw = dw || sw; 817 | dh = dh || sh; 818 | if (sx >= 0 && sy >= 0 && sw > 0 && sh > 0 && dw > 0 && dh > 0 && 819 | sx + sw <= source.width && sy + sh <= source.height 820 | ) { 821 | this._context.globalCompositeOperation = 'source-over'; 822 | const offsetX = dx + dw/2; 823 | const offsetY = dy + dh/2; 824 | this._context.translate(offsetX, offsetY); 825 | this._context.rotate(angle * Math.PI / 180); 826 | this._context.translate(-offsetX, -offsetY); 827 | this._context.drawImage(source._canvas, sx, sy, sw, sh, dx, dy, dw, dh); 828 | this._context.setTransform(1, 0, 0, 1, 0, 0); 829 | this._setDirty(); 830 | } 831 | }; 832 | } 833 | 834 | 835 | 836 | // Function to debug any sounds when we don't want to run sounds. 837 | // Usage: open the console and run DebugSound(); 838 | 839 | // TODO: Add AudioManager, etc. 840 | 841 | DebugSound = function() { 842 | this.playSystemSound = function() { 843 | console.log('SoundManager.splaySystemSound'); 844 | }; 845 | this.playCursor = function() { 846 | console.log('SoundManager.playCursor'); 847 | }; 848 | this.playOk = function() { 849 | console.log('SoundManager.playOk'); 850 | }; 851 | this.playCancel = function() { 852 | console.log('SoundManager.playCancel'); 853 | }; 854 | this.playBuzzer = function() { 855 | console.log('SoundManager.playBuzzer'); 856 | }; 857 | this.playEquip = function() { 858 | console.log('SoundManager.playEquip'); 859 | }; 860 | this.playSave = function() { 861 | console.log('SoundManager.playSave'); 862 | }; 863 | this.playLoad = function() { 864 | console.log('SoundManager.playLoad'); 865 | }; 866 | this.playBattleStart = function() { 867 | console.log('SoundManager.playBattleStart'); 868 | }; 869 | this.playEscape = function() { 870 | console.log('SoundManager.playEscape'); 871 | }; 872 | this.playEnemyAttack = function() { 873 | console.log('SoundManager.playEnemyAttack'); 874 | }; 875 | this.playEnemyDamage = function() { 876 | console.log('SoundManager.playEnemyDamage'); 877 | }; 878 | this.playEnemyCollapse = function() { 879 | console.log('SoundManager.playEnemyCollapse'); 880 | }; 881 | this.playBossCollapse1 = function() { 882 | console.log('SoundManager.playBossCollapse1'); 883 | }; 884 | this.playBossCollapse2 = function() { 885 | console.log('SoundManager.playBossCollapse2'); 886 | }; 887 | this.playActorDamage = function() { 888 | console.log('SoundManager.playActorDamage'); 889 | }; 890 | this.playActorCollapse = function() { 891 | console.log('SoundManager.playActorCollapse'); 892 | }; 893 | this.playRecovery = function() { 894 | console.log('SoundManager.playRecovery'); 895 | }; 896 | this.playMiss = function() { 897 | console.log('SoundManager.playMiss'); 898 | }; 899 | this.playEvasion = function() { 900 | console.log('SoundManager.playEvasion'); 901 | }; 902 | this.playMagicEvasion = function() { 903 | console.log('SoundManager.playMagicEvasion'); 904 | }; 905 | this.playReflection = function() { 906 | console.log('SoundManager.playReflection'); 907 | }; 908 | this.playShop = function() { 909 | console.log('SoundManager.playShop'); 910 | }; 911 | this.playUseItem = function() { 912 | console.log('SoundManager.playUseItem'); 913 | }; 914 | this.playUseSkill = function() { 915 | console.log('SoundManager.playUseSkill]'); 916 | }; 917 | 918 | SoundManager = this; 919 | } 920 | 921 | /* Scene Tests */ 922 | function isScene(name) { 923 | return SceneManager._scene instanceof name; 924 | } 925 | 926 | function isSceneDeep(name) { 927 | let result = isScene(name); 928 | if(!result) { 929 | for(let i = 0; i < SceneManager._stack.length; i++) { 930 | let temp = new SceneManager._stack[i]; 931 | result = result || temp instanceof name; 932 | delete temp; 933 | if(result) break; 934 | } 935 | } 936 | return result; 937 | } 938 | -------------------------------------------------------------------------------- /Kru_Demo.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Krusynth Demo 3 | // Version: 1.0.0 4 | //============================================================================= 5 | /*: 6 | * @plugindesc 1.0.0 Helper for demos of plugins. 7 | * 8 | * @author Krusynth 9 | * 10 | * @param Path 11 | * @desc Path for images and audio files. 12 | * @default ./ 13 | * 14 | * @param Container 15 | * @desc Id of the HTML element to load the game into. Defaults to the document body. 16 | * @default 17 | * 18 | * @help 19 | * ============================================================================ 20 | * Information 21 | * ============================================================================ 22 | * 23 | * This is the base include for many Krusynth RPG Maker MV plugins. It includes 24 | * a JSON loader and window manager. 25 | */ 26 | 27 | var Imported = Imported || {}; 28 | Imported.Kru_Demo = "1.0.0"; 29 | 30 | var Kru = Kru || {}; 31 | Kru.Demo = { 32 | config: {} 33 | }; 34 | 35 | Kru.Demo.params = PluginManager.parameters('Kru_Demo'); 36 | 37 | Kru.Demo.elm = document.body; 38 | if(Kru.Demo.params.Container) { 39 | Kru.Demo.elm = document.getElementById(Kru.Demo.params.Container); 40 | } 41 | 42 | /* Fix all of the asset load paths. */ 43 | Kru.Demo.fixUrl = function(url) { 44 | return url.replace(/^/, Kru.Demo.params['Path']); 45 | } 46 | 47 | Kru.Demo.Bitmap_load = Bitmap.load; 48 | Bitmap.load = function(url) { 49 | return Kru.Demo.Bitmap_load.call(this, Kru.Demo.fixUrl(url)); 50 | }; 51 | 52 | Kru.Demo.Bitmap_request = Bitmap.request; 53 | Bitmap.request = function(url) { 54 | return Kru.Demo.Bitmap_request.call(this, Kru.Demo.fixUrl(url)); 55 | } 56 | 57 | Kru.Demo.Graphics_setLoadingImage = Graphics.setLoadingImage; 58 | Graphics.setLoadingImage = function(src) { 59 | return Kru.Demo.Graphics_setLoadingImage.call(this, Kru.Demo.fixUrl(src)); 60 | }; 61 | 62 | AudioManager._path = Kru.Demo.fixUrl(AudioManager._path); 63 | 64 | /* Load the game into a custom html container. */ 65 | /* Override every instance of document.body. */ 66 | Graphics._createErrorPrinter = function() { 67 | this._errorPrinter = document.createElement('p'); 68 | this._errorPrinter.id = 'ErrorPrinter'; 69 | this._updateErrorPrinter(); 70 | Kru.Demo.elm.appendChild(this._errorPrinter); 71 | }; 72 | 73 | Graphics._createCanvas = function() { 74 | this._canvas = document.createElement('canvas'); 75 | this._canvas.id = 'GameCanvas'; 76 | this._updateCanvas(); 77 | Kru.Demo.elm.appendChild(this._canvas); 78 | }; 79 | 80 | Graphics._createVideo = function() { 81 | this._video = document.createElement('video'); 82 | this._video.id = 'GameVideo'; 83 | this._video.style.opacity = 0; 84 | this._video.setAttribute('playsinline', ''); 85 | this._video.volume = this._videoVolume; 86 | this._updateVideo(); 87 | makeVideoPlayableInline(this._video); 88 | Kru.Demo.elm.appendChild(this._video); 89 | }; 90 | 91 | Graphics._createUpperCanvas = function() { 92 | this._upperCanvas = document.createElement('canvas'); 93 | this._upperCanvas.id = 'UpperCanvas'; 94 | this._updateUpperCanvas(); 95 | Kru.Demo.elm.appendChild(this._upperCanvas); 96 | }; 97 | 98 | Graphics._createModeBox = function() { 99 | var box = document.createElement('div'); 100 | box.id = 'modeTextBack'; 101 | box.style.position = 'absolute'; 102 | box.style.left = '5px'; 103 | box.style.top = '5px'; 104 | box.style.width = '119px'; 105 | box.style.height = '58px'; 106 | box.style.background = 'rgba(0,0,0,0.2)'; 107 | box.style.zIndex = 9; 108 | box.style.opacity = 0; 109 | 110 | var text = document.createElement('div'); 111 | text.id = 'modeText'; 112 | text.style.position = 'absolute'; 113 | text.style.left = '0px'; 114 | text.style.top = '41px'; 115 | text.style.width = '119px'; 116 | text.style.fontSize = '12px'; 117 | text.style.fontFamily = 'monospace'; 118 | text.style.color = 'white'; 119 | text.style.textAlign = 'center'; 120 | text.style.textShadow = '1px 1px 0 rgba(0,0,0,0.5)'; 121 | text.innerHTML = this.isWebGL() ? 'WebGL mode' : 'Canvas mode'; 122 | 123 | Kru.Demo.elm.appendChild(box); 124 | box.appendChild(text); 125 | 126 | this._modeBox = box; 127 | }; 128 | 129 | Graphics._createFontLoader = function(name) { 130 | var div = document.createElement('div'); 131 | var text = document.createTextNode('.'); 132 | div.style.fontFamily = name; 133 | div.style.fontSize = '0px'; 134 | div.style.color = 'transparent'; 135 | div.style.position = 'absolute'; 136 | div.style.margin = 'auto'; 137 | div.style.top = '0px'; 138 | div.style.left = '0px'; 139 | div.style.width = '1px'; 140 | div.style.height = '1px'; 141 | div.appendChild(text); 142 | Kru.Demo.elm.appendChild(div); 143 | }; -------------------------------------------------------------------------------- /Kru_ExtraMovementFramesPatch.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Kru_ExtraMovementFramesPatch.js 3 | //============================================================================= 4 | 5 | /*: 6 | * @plugindesc Patches Modern Algebra's Extra Movement Frames to fix web bugs. 7 | * @author Krusynth 8 | * 9 | * @param Pattern 10 | * @desc Pattern to match for the filename 11 | * @default \%[\(\[]([\d\s]*)[\)\]](@[0-9]+)? 12 | * 13 | * @help This plugin extends Modern Algebra's Extra Movement Frames to fix an 14 | * issue with the default filename pattern, which breaks on the web due to the 15 | * use of the % character. Allows users to set their own regex patterns. 16 | * 17 | * The default cycle time can now also be set in the pattern, by using a second 18 | * matching group. 19 | */ 20 | 21 | var Kru = Kru || {}; 22 | Kru.EMFP = { 23 | }; 24 | 25 | Kru.EMFP.params = PluginManager.parameters('Kru_ExtraMovementFramesPatch'); 26 | Kru.EMFP.params['Pattern'] = new RegExp(Kru.EMFP.params['Pattern']); 27 | 28 | ImageManager.isEmfCharacter = function(filename) { 29 | return !!filename.match(Kru.EMFP.params['Pattern']); 30 | }; 31 | 32 | Game_CharacterBase.prototype.maemfSetupEmfCharacter = function() { 33 | this.maClearEmfCharacterState(); 34 | let charName = this.characterName(); 35 | if (ImageManager.isEmfCharacter(charName)) { 36 | this._isEmfCharacter = true; 37 | let sign = charName.match(Kru.EMFP.params['Pattern']); 38 | let signArgs = []; 39 | if(sign[1].trim().length) { 40 | signArgs = sign[1].trim().split(' ').map(Number); // array of digit strings 41 | } 42 | 43 | this.cycleTime = typeof sign[2] == 'string' ? parseInt(sign[2].match(/[0-9]+/)) : ModernAlgebra.EMF.cycleTime; 44 | // Map arguments in file name to an array of numbers 45 | 46 | if(signArgs.length) { 47 | this.emfCharacterState().frameNum = signArgs.shift(); 48 | this.emfCharacterState().idleFrame = (signArgs.length > 1) ? signArgs.shift() : ModernAlgebra.EMF.idleFrame; 49 | } 50 | 51 | if (signArgs.length > 2) { 52 | this.emfCharacterState().pattern = signArgs; 53 | } else { 54 | let success = false; 55 | // Check for a default match for this number of frames 56 | for (let i = 0; i < ModernAlgebra.EMF.defaultPattern.length; i++) { 57 | if (ModernAlgebra.EMF.defaultPattern[i][0] === this.emfCharacterState().frameNum) { 58 | this.emfCharacterState().idleFrame = ModernAlgebra.EMF.defaultPattern[i][1]; 59 | this.emfCharacterState().pattern = ModernAlgebra.EMF.defaultPattern[i].slice(2, (ModernAlgebra.EMF.defaultPattern[i].length)); 60 | success = true; 61 | break; 62 | } 63 | } 64 | // If still no pattern specified 65 | if (!success) { 66 | // Populate pattern with a simple cycle starting after idle 67 | this.emfCharacterState().pattern = []; 68 | let idleFramePlus = this.emfCharacterState().idleFrame + 1; 69 | for (let i = 0; i < this.emfCharacterState().frameNum; i++) { 70 | this.emfCharacterState().pattern.push((i + idleFramePlus) % this.emfCharacterState().frameNum); 71 | } 72 | } 73 | } 74 | } 75 | }; 76 | 77 | Game_CharacterBase.prototype.animationWait = function() { 78 | // If EMF Character 79 | if (this.isEmfCharacter()) { 80 | let realSpeed = this.realMoveSpeed(); 81 | let frameNum = this.maxPattern(); 82 | return Math.floor((8 - realSpeed)*(this.cycleTime / (4*frameNum))); // CycleTime divided by number of frames in animation 83 | } else { 84 | // Run Default Method - approx. 60 frames at normal speed 85 | return ModernAlgebra.EMF.GameCharacterBase_animationWait.apply(this, arguments) // original method 86 | } 87 | }; -------------------------------------------------------------------------------- /Kru_GameSeed.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Game Seed 3 | // Version: 1.0.0 4 | //============================================================================= 5 | /*: 6 | * @plugindesc v1.0.0 Creates a custom random seed for the game. 7 | * 8 | * @author Krusynth 9 | * 10 | * @param Seed Variable Name 11 | * @desc Select the variable that should hold the seed. 12 | * @type variable 13 | * 14 | * @help 15 | * ============================================================================ 16 | * Information 17 | * ============================================================================ 18 | * 19 | * This plugin creates a random number to associate with the current game. This 20 | * number is only set once per game, so it can be used to create stable events. 21 | * Combine this with Hime's Custom Page Conditions to randomize parts of maps! 22 | * 23 | * Usage example: 24 | * 25 | * To have an event show up randomly, use Custom Page Conditions with 26 | * 27 | * Terms & Conditions 28 | * This plugin is free for non-commercial and commercial use. 29 | */ 30 | 31 | var Imported = Imported || {}; 32 | Imported.Kru_GS = "1.0.0"; 33 | 34 | var Kru = Kru || {}; 35 | Kru.GS = { 36 | config: {} 37 | }; 38 | 39 | Kru.GS.Parameters = PluginManager.parameters('Kru_GameSeed'); 40 | Kru.GS.SeedVar = Kru.GS.Parameters['Seed Variable Name']; 41 | 42 | Kru.GS.generateSeed = function () { 43 | return Math.floor(Math.random() * 100000000); 44 | } 45 | 46 | // Usage 47 | Kru.GS.seedTest = function(num, position) { 48 | let value = $gameVariables._data[Kru.GS.SeedVar]; 49 | 50 | if(num) { 51 | if(position) { 52 | value = Math.floor( value / (10 ** position) ); 53 | } 54 | 55 | return value % num; 56 | } 57 | return; 58 | } 59 | // Shortcut 60 | var seedTest = Kru.GS.seedTest; 61 | 62 | Kru.GS.setSeed = function() { 63 | if(typeof $gameVariables._data[Kru.GS.SeedVar] === 'undefined') { 64 | $gameVariables._data[Kru.GS.SeedVar] = Kru.GS.generateSeed(); 65 | } 66 | } 67 | 68 | Kru.GS.DataManager__setupNewGame = DataManager.setupNewGame; 69 | DataManager.setupNewGame = function() { 70 | Kru.GS.DataManager__setupNewGame.call(this); 71 | 72 | Kru.GS.setSeed(); 73 | }; 74 | 75 | Kru.GS.DataManager__loadGameWithoutRescue = DataManager.loadGameWithoutRescue; 76 | DataManager.loadGameWithoutRescue = function(savefileId) { 77 | let result = Kru.GS.DataManager__loadGameWithoutRescue.call(this, savefileId); 78 | Kru.GS.setSeed(); 79 | 80 | return result; 81 | }; 82 | -------------------------------------------------------------------------------- /Kru_LoadImageTypes.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Kru_LoadImageTypes.js 3 | //============================================================================= 4 | 5 | /*: 6 | * @plugindesc Enables loading image files other than pngs in most use cases. 7 | * @author Krusynth 8 | * 9 | * @help If you include a file extension, that file will be used. If not, ".png" 10 | * is added per usual. 11 | */ 12 | 13 | ImageManager.loadBitmap = function(folder, filename, hue, smooth) { 14 | if (filename) { 15 | if (!filename.match(/\.[a-z]{2,4}$/) ) { 16 | filename += '.png'; 17 | } 18 | 19 | let path = folder + encodeURIComponent(filename); 20 | let bitmap = this.loadNormalBitmap(path, hue || 0); 21 | bitmap.smooth = smooth; 22 | return bitmap; 23 | } else { 24 | return this.loadEmptyBitmap(); 25 | } 26 | }; -------------------------------------------------------------------------------- /Kru_MapLoadEvents.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Kru_MapLoadEvents.js 3 | //============================================================================= 4 | 5 | /*: 6 | * @plugindesc Runs scripts on map change. 7 | * @author Krusynth 8 | * 9 | * @help This plugin allows for custom javascript to be run on map load. Add a 10 | * load tag and follow it with whatever code you want to execute. 11 | * 12 | * Example: 13 | * 14 | * 15 | * TODO: Add global events. 16 | * 17 | 18 | */ 19 | 20 | var Kru = Kru || {}; 21 | Kru.MLE = { 22 | }; 23 | 24 | // Automatically switch parties on transfer if the map has a party tag. 25 | Kru.MLE.Game_Player__performTransfer = Game_Player.prototype.performTransfer; 26 | Game_Player.prototype.performTransfer = function() { 27 | if( 28 | $dataMap.meta && 29 | typeof $dataMap.meta.load !== 'undefined' 30 | ) { 31 | eval($dataMap.meta.load); 32 | } 33 | Kru.MLE.Game_Player__performTransfer.call(this); 34 | } 35 | -------------------------------------------------------------------------------- /Kru_MapMerge.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Map Merge 3 | // Version: 1.0.0 4 | //============================================================================= 5 | /*: 6 | * @plugindesc v1.0.0 Merges maps if conditions are met. 7 | * 8 | * @author Krusynth 9 | * 10 | * @help 11 | * ============================================================================ 12 | * Information 13 | * ============================================================================ 14 | * 15 | * This plugin allows authors to replace a section of a map with a new map 16 | * when a given set of conditions are met. 17 | * 18 | * Usage 19 | * Add a line to the parent map's notes field with a JSON object in the 20 | * following format. The id is the id number of the child map to use. You can 21 | * find this number at the bottom of the map window in RPG Maker MV. 22 | * 23 | * {"mapmerge":[{"condition":"$gameActors._data[1]._level > 10","mapId":40,"offset":{"x":4,"y":4}}]} 24 | * 25 | * In this example, map 40 will be inserted into the current map at [4,4], if 26 | * the first actor is above level 10. 27 | * 28 | * Terms & Conditions 29 | * This plugin is free for non-commercial and commercial use. 30 | */ 31 | 32 | var Imported = Imported || {}; 33 | Imported.Kru_MapMerge = "1.0.0"; 34 | 35 | var Kru = Kru || {}; 36 | Kru.MapMerge = { 37 | config: {} 38 | }; 39 | 40 | if(!Imported.Kru_Core) { 41 | alert('Kru_StatOverhaul requires Kru_Core.'); 42 | throw new Error('Kru_StatOverhaul requires Kru_Core.'); 43 | } 44 | 45 | Kru.MapMerge.DataManager_loadMapData = DataManager.loadMapData; 46 | DataManager.loadMapData = function(mapId) { 47 | if (mapId > 0) { 48 | $dataMap = Kru.helpers.getMapData(mapId, Kru.MapMerge.processMap); 49 | 50 | Kru.MapMerge.processMap($dataMap); 51 | } else { 52 | this.makeEmptyMap(); 53 | } 54 | } 55 | 56 | Kru.MapMerge.processMap = function(parentMap) { 57 | let notes = Kru.helpers.parseNoteTags(parentMap.note); 58 | 59 | if(typeof(notes.mapmerge) !== 'undefined') { 60 | for(gms_i = 0; gms_i < notes.mapmerge.length; gms_i++) { 61 | let map = notes.mapmerge[gms_i]; 62 | if( 63 | map.mapId && 64 | (typeof(map.condition) === 'undefined' || 65 | eval(map.condition)) 66 | ) { 67 | let mapData = Kru.helpers.getMapData(map.mapId); 68 | 69 | let offset = {x:0, y:0}; 70 | if(map.offset) { 71 | offset = map.offset; 72 | } 73 | 74 | Kru.MapMerge.mapMergeTiles(parentMap, mapData, offset); 75 | Kru.MapMerge.mapMergeEvents(parentMap, mapData, offset); 76 | } 77 | } 78 | } 79 | }; 80 | 81 | Kru.MapMerge.mapMergeTiles = function(map1, map2, offset) { 82 | offset = offset || {}; 83 | offset.x = offset.x || 0; 84 | offset.y = offset.y || 0; 85 | 86 | // Depth (Z) is generally the same for all maps. 87 | let depth = map1.data.length / (map1.width * map1.height); 88 | 89 | let height = map2.height; 90 | if(height > map1.height) { 91 | height = map1.height; 92 | } 93 | 94 | let width = map2.width; 95 | if(width > map1.width) { 96 | width = map1.width; 97 | } 98 | 99 | // Depth 100 | for(let z = 0; z < depth; z++) { 101 | // Rows 102 | for(let y = 0; y < height; y++) { 103 | // Columns 104 | for(let x = 0; x < width; x++) { 105 | let idx1 = ((z * map1.height) + (y + offset.y)) * map1.width + offset.x + x; 106 | let idx2 = (z * map2.height + y) * map2.width + x 107 | 108 | // Remap our tile. 109 | map1.data[idx1] = map2.data[idx2]; 110 | } 111 | } 112 | } 113 | } 114 | 115 | Kru.MapMerge.mapMergeEvents = function(map1, map2, offset) { 116 | offset = offset || {}; 117 | offset.x = offset.x || 0; 118 | offset.y = offset.y || 0; 119 | 120 | for(let i = 0; i < map2.events.length; i++) { 121 | let event = map2.events[i]; 122 | if(event) { 123 | // Increment our id. 124 | event.id = map1.events.length; 125 | 126 | event.x += offset.x; 127 | event.y += offset.y; 128 | 129 | if(typeof(event.meta) === 'undefined') { 130 | event.meta = {}; 131 | } 132 | 133 | map1.events.push(event); 134 | } 135 | } 136 | } 137 | 138 | // Remove extra map load when the map hasn't changed on scene load. 139 | // This fixes the issue where exiting the menu resets the map. 140 | Kru.MapMerge.Scene_Map_create = Scene_Map.prototype.create; 141 | Scene_Map.prototype.create = function() { 142 | Scene_Base.prototype.create.call(this); 143 | this._transfer = $gamePlayer.isTransferring(); 144 | // Here's what we're changing. 145 | if(this._transfer) { 146 | DataManager.loadMapData($gamePlayer.newMapId()); 147 | } 148 | }; 149 | -------------------------------------------------------------------------------- /Kru_MultitileEvents.js: -------------------------------------------------------------------------------- 1 | /*: 2 | * Multitle Events 3 | * 4 | * @plugindesc 1.0 Allows for events that are bigger than 1 tile. 5 | * 6 | * @author Krusynth 7 | * 8 | * @help 9 | * This plugin allows for events that are bigger than one tiles, by 10 | * expanding the collision box via notes. This works nicely for 11 | * larger sprites and allows for movement per normal. This tag uses 12 | * JSON in the notes field, instead of tags. 13 | * 14 | * By default all events are 1 tile high and 1 tile wide. To make a 15 | * larger event add a note of the format {"size": {"w": #, "h": #}} 16 | * where the h and w are the number of tiles to *add* to the height 17 | * and width respectively. For example, {"size":{"w":[-1,1],"h":2}} 18 | * will result in a 2-tile tall, 1 tile wide event. 19 | * 20 | * You can also specify an offset from the main event tile by using 21 | * a pair of values e.g.: {"size": {"w": [-1,1], "h": [-1,1]}} 22 | * will result in a 3x3 entity centered on the event's location. 23 | * 24 | * These are evaluated when the event is loaded for the map, not 25 | * when the data is loaded. 26 | * 27 | * Terms & Conditions 28 | * This plugin is MIT Licensed. (Free for non-commercial and commercial use.) 29 | */ 30 | 31 | var Imported = Imported || {}; 32 | Imported.Kru_MultitileEvents = 1.0; 33 | 34 | var Kru = Kru || {}; 35 | Kru.MT = { 36 | config: {} 37 | }; 38 | 39 | if(!Imported.Kru_Core) { 40 | alert('Kru_MultitileEvents requires Kru_Core.'); 41 | throw new Error('Kru_MultitileEvents requires Kru_Core.'); 42 | } 43 | 44 | Game_CharacterBase.prototype._w = 0; 45 | Game_CharacterBase.prototype._h = 0; 46 | 47 | Kru.MT.Game_Event__initialize = Game_Event.prototype.initialize; 48 | Game_Event.prototype.initialize = function(mapId, eventId) { 49 | Game_Character.prototype.initialize.call(this); 50 | this._mapId = mapId; 51 | this._eventId = eventId; 52 | let event = this.event(); 53 | // event.meta = Kru.helpers.parseNoteTags(event.note); 54 | 55 | this.Kru_handleSizing(event); 56 | this.locate(event.x, event.y); 57 | this.refresh(); 58 | }; 59 | 60 | Game_Event.prototype.Kru_handleSizing = function(event) { 61 | if( 62 | typeof(event.meta) !== 'undefined' && 63 | typeof(event.meta.size) !== 'undefined' 64 | ) { 65 | let size = event.meta.size; 66 | 67 | if(typeof size.w !== 'undefined') { 68 | // If we have only one number, start at zero. 69 | if(!Array.isArray(size.w)) { 70 | this._w = [0, size.w]; 71 | } 72 | else { 73 | this._w = size.w; 74 | } 75 | } 76 | else { 77 | this._w = [0, 0]; 78 | } 79 | 80 | if(typeof size.h !== 'undefined') { 81 | // If we have only one number, start at zero. 82 | if(!Array.isArray(size.h)) { 83 | this._h = [0, size.h]; 84 | } 85 | else { 86 | this._h = size.h; 87 | } 88 | } 89 | else { 90 | this._h = [0, 0]; 91 | } 92 | } 93 | } 94 | 95 | Game_CharacterBase.prototype.pos = function(x, y) { 96 | if(this._w && this._h) { 97 | return (x >= this._x + this._w[0] && x <= this._x + this._w[1] && 98 | y >= this._y + this._h[0] && y <= this._y + this._h[1]); 99 | } 100 | else { 101 | return (x === this._x && y === this._y); 102 | } 103 | }; 104 | 105 | // Fix collision checking to ignore itself. 106 | Game_Event.prototype.isCollidedWithEvents = function(x, y) { 107 | let events = $gameMap.eventsXyNt(x, y).filter(function(event) { 108 | return (event._eventId !== this._eventId); 109 | }.bind(this)); 110 | return events.length > 0; 111 | }; 112 | 113 | // We need to check if we can move to the location, multitile. 114 | Game_Event.prototype.canPassOrig = Game_Event.prototype.canPass; 115 | Game_Event.prototype.canPass = function(init_x, init_y, d) { 116 | for(var x = init_x + this._w[0]; x <= init_x + this._w[1]; x++) { 117 | for(var y = init_y + this._h[0]; y <= init_y + this._h[1]; y++) { 118 | if(!this.canPassOrig(x, y, d)) { 119 | // console.log('cant pass', init_x, init_y, this._w, this._h, x, y, d); 120 | return false; 121 | } 122 | } 123 | } 124 | return true; 125 | } 126 | -------------------------------------------------------------------------------- /Kru_PartyWindow.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Party Window 3 | // Version: 1.0.0 4 | //============================================================================= 5 | /*: 6 | * @plugindesc v1.0.0 Shows more characters in windows based on 7 | * Max Battle Members setting in Yanfly's Party System. 8 | * 9 | * @author Krusynth 10 | * 11 | * @param ---General--- 12 | * @default 13 | * 14 | * @help 15 | * ============================================================================ 16 | * Information 17 | * ============================================================================ 18 | * This plugin requires Yanfly's Party System. It uses the value of 19 | * Max Battle Members set in that plugin to determine how many party members to 20 | * show on the status screen. Note that past 5 members, the font will be too 21 | * big to fit all of the information on the screen. 22 | * 23 | * Terms & Conditions 24 | * This plugin is free for non-commercial and commercial use. 25 | */ 26 | 27 | var Imported = Imported || {}; 28 | Imported.Kru_PartyWindow = "1.0.0"; 29 | 30 | var Kru = Kru || {}; 31 | Kru.PW = { 32 | config: {} 33 | }; 34 | 35 | Kru.PW.Parameters = PluginManager.parameters('Kru_PartyWindow'); 36 | 37 | Kru.PW.Window_MenuStatus__numVisibleRows = Window_MenuStatus.prototype.numVisibleRows; 38 | Window_MenuStatus.prototype.numVisibleRows = function() { 39 | return Yanfly.Param.MaxBattleMembers; 40 | }; 41 | 42 | /* 43 | * This overrides YEP_BattleEngineCore.js 44 | */ 45 | Kru.PW.Window_BattleStatus__numVisibleRows = Window_BattleStatus.prototype.numVisibleRows 46 | Window_BattleStatus.prototype.numVisibleRows = function() { 47 | return Yanfly.Param.MaxBattleMembers; 48 | }; 49 | -------------------------------------------------------------------------------- /Kru_PipeMinigame.js: -------------------------------------------------------------------------------- 1 | /*: 2 | * Pipe Minigame 3 | * 4 | * @plugindesc 1.1 Creates a pipe minigame. 5 | * 6 | * @author Krusynth (https://billhunt.dev) 7 | * 8 | * @help 9 | * 10 | * Terms & Conditions 11 | * This plugin is MIT Licensed. (Free for non-commercial and commercial use.) 12 | * 13 | * Usage: add a custom script to an event, and run pipeminigame(); 14 | * 15 | * You can pass parameters as well. E.g. pipeminigame({pieces: 3, rotate: true}) 16 | * will allow the player to pick from three pieces and allow rotation of pieces. 17 | * 18 | * You'll need to check a variable within $gameTemp to see if the player 19 | * succeeded. This is customizable in the paramters, defaults to 20 | * $gameTemp['kru_pipegame']; 21 | * 22 | * Important: you'll need to create a tiles image for the game, Please see the 23 | * example file here: https://raw.githubusercontent.com/wiki/krusynth/rpgmakermv-plugins/img/Kru_PipeMinigame/pipetiles.png 24 | * 25 | * @param Title 26 | * @default Pipe Game 27 | * @desc Title of the window 28 | * 29 | * @param Variable 30 | * @default kru_pipegame 31 | * @desc The key to store the result of the minigame within $gameTemp 32 | * 33 | * @param Icons 34 | * @desc Name of the tiles image to use, in img/system, without the file extension. 35 | * @type file 36 | * @default pipetiles 37 | * @dir img/system 38 | * 39 | * @param Icon Size 40 | * @parent Icons 41 | * @type number 42 | * @desc Size of the icons to use. It's not recommended to change this. 43 | * @default 72 44 | */ 45 | 46 | var Imported = Imported || {}; 47 | Imported.Kru_PipeMinigame = 1.1; 48 | 49 | var Kru = Kru || {}; 50 | Kru.PM = { 51 | config: {} 52 | }; 53 | 54 | Kru.PM.params = PluginManager.parameters('Kru_PipeMinigame'); 55 | Kru.PM.params['Icon Size'] = parseInt(Kru.PM.params['Icon Size']); 56 | 57 | if(!Imported.Kru_Core) { 58 | alert('Kru_PipeMinigame requires Kru_Core.'); 59 | throw new Error('Kru_PipeMinigame requires Kru_Core.'); 60 | } 61 | 62 | function pipeminigame(args) { 63 | args = args || {}; 64 | $gameTemp[Kru.PM.params['Variable']] = null; 65 | SceneManager.push(Function.prototype.bind.call(Scene_PipeMinigame, null, args)); 66 | } 67 | 68 | class Scene_PipeMinigame extends Scene_MenuBase { 69 | 70 | async initialize(args) { 71 | args = args || {}; 72 | this.icon = args.icon || { 73 | set: Kru.PM.params['Icons'], 74 | width: Kru.PM.params['Icon Size'], 75 | height: Kru.PM.params['Icon Size'] 76 | }; 77 | this.args = args; 78 | 79 | super.initialize(args); 80 | 81 | await this.loadIcons(); 82 | } 83 | 84 | loadIcons(name) { 85 | name = name || this.icon.set; 86 | 87 | if(!this.bitmap) { 88 | this.bitmap = ImageManager.loadSystem(name); 89 | let wait = true; 90 | return new Promise(resolve => { 91 | this.bitmap.addLoadListener(() => { 92 | resolve(); 93 | }); 94 | }); 95 | } 96 | } 97 | 98 | create() { 99 | super.create(); 100 | // With our current window settings, 46px appears to be the chrome width. 101 | let _magicNumber = 46; 102 | let leftWidth = this.icon.width + _magicNumber; 103 | let rightWidth = Graphics.boxWidth - leftWidth; 104 | 105 | const wm = Kru.helpers.WindowManager(this); 106 | 107 | const titleWindow = wm.addWindow({ 108 | width: 1, 109 | height: .12, 110 | content: Kru.PM.params['Title'] 111 | }); 112 | 113 | const pieceWindow = wm.addWindow({ 114 | name: 'pieceWindow', 115 | // width: .2, 116 | _w: leftWidth, 117 | height: this.args.rotate ? .76 : .88, 118 | type: 'piecelist', 119 | icon: this.icon, 120 | pieces: this.args.pieces, 121 | rotate: this.args.rotate 122 | }); 123 | 124 | // We want to put the exit box underneath this, so we save our position. 125 | let bottom = wm.last._y + wm.last._h; 126 | 127 | const gridWindow = wm.addWindow({ 128 | name: 'gridWindow', 129 | // width: .8, 130 | _w: rightWidth, 131 | height: .88, 132 | type: 'gamegrid', 133 | icon: this.icon 134 | }); 135 | 136 | if(this.args.rotate) { 137 | const opWindow = wm.addWindow({ 138 | // width: .2, 139 | _w: leftWidth, 140 | height: .12, 141 | content: ' ➡: ⤵', 142 | _x: 0, 143 | _y: bottom 144 | }); 145 | } 146 | 147 | pieceWindow.grid = gridWindow; 148 | gridWindow.pieceWindow = pieceWindow; 149 | 150 | pieceWindow.activate(); 151 | pieceWindow.select(0); 152 | 153 | // TODO: use reference to this.bitmap in derived windows. 154 | 155 | return; 156 | } 157 | } 158 | 159 | /* 160 | * Create a window to show our available pieces. 161 | */ 162 | class Kru_PipeGame_PieceListWindow extends Kru_GenericListWindow { 163 | 164 | initialize(win) { 165 | this.pieces = win.pieces || 1; 166 | this.frequency = win.frequency || 167 | { 168 | 'PieceL': 7, 169 | 'PieceI': 4, 170 | 'PieceT': 2, 171 | 'PieceX': 1, 172 | }; 173 | 174 | this.rotate = true; 175 | if(typeof win.rotate !== 'undefined') { 176 | this.rotate = win.rotate; 177 | } 178 | 179 | this._data = []; 180 | 181 | this._margin = win.margin || 10; 182 | this._offset = 5; 183 | 184 | this.setFrequency(); 185 | this.initPieces(); 186 | super.initialize(win); 187 | 188 | this.setHandler('ok', this.onOk.bind(this)); 189 | this.setHandler('cancel', this.onCancel.bind(this)); 190 | } 191 | 192 | async refresh() { 193 | await this.loadIcons(); 194 | super.refresh(); 195 | } 196 | 197 | initPieces() { 198 | for(let i = 0; i < this.pieces; i++) { 199 | this._data[i] = this.getPiece(); 200 | } 201 | } 202 | 203 | getPiece() { 204 | let value = Math.floor(Math.random() * this._maxFrequency); 205 | 206 | let keys = Object.keys(this._frequency); 207 | let piece = null; 208 | 209 | for(let i = 0; i < keys.length; i++) { 210 | let key = keys[i]; 211 | if(value < this._frequency[key]) { 212 | piece = new Kru.PM.pieces[key](); 213 | // Randomize our rotation. 214 | piece.direction = Math.floor(Math.random() * piece.connections.length); 215 | 216 | break; 217 | } 218 | } 219 | return piece; 220 | } 221 | 222 | use() { 223 | let result = Object.assign({}, this.current); 224 | this._data[this.index()] = this.getPiece(); 225 | this.refresh(); 226 | 227 | return result; 228 | } 229 | 230 | setFrequency() { 231 | this._frequency = {}; 232 | let keys = Object.keys(this.frequency); 233 | let sum = 0; 234 | for(let i = 0; i < keys.length; i++) { 235 | let key = keys[i]; 236 | sum += this.frequency[key]; 237 | this._frequency[key] = sum; 238 | } 239 | this._maxFrequency = sum; 240 | } 241 | 242 | onOk() { 243 | this.grid.piece = this.data 244 | this.grid.activate(); 245 | } 246 | 247 | onCancel() { 248 | // Result = fail. 249 | $gameTemp[Kru.PM.params['Variable']] = false; 250 | 251 | this._win.scene.popScene(); 252 | } 253 | 254 | drawItem(index) { 255 | let piece = this._data[index]; 256 | let pos = this.positionAdjusted(index); 257 | 258 | this.drawIconIndex(piece.img[0], piece.img[1], 259 | pos[0]+this._offset, pos[1]+this._offset, piece.rotation); 260 | } 261 | 262 | itemRect(index) { 263 | let rect = new Rectangle(); 264 | let pos = this.positionAdjusted(index); 265 | 266 | rect.x = pos[0]; 267 | rect.y = pos[1]; 268 | rect.width = this._iconWidth + (this._offset * 2); 269 | rect.height = this._iconHeight + (this._offset * 2); 270 | 271 | return rect; 272 | } 273 | 274 | positionAdjusted(index) { 275 | let x = 0; 276 | let y = (this._iconHeight + this._margin) * index; 277 | 278 | return [x, y]; 279 | } 280 | 281 | select(index) { 282 | this._index = index; 283 | this._stayCount = 0; 284 | this.ensureCursorVisible(); 285 | this.updateCursor(); 286 | } 287 | 288 | // The piece window is a single row, but pieces are rotatable from this window. 289 | cursorDown(wrap) { 290 | if(this.maxItems() === 1) return; 291 | 292 | let newIndex = null; 293 | if(this.index() == this.maxItems() - 1 && wrap) { 294 | this.select(0); 295 | } 296 | else { 297 | this.select(this.index()+1); 298 | } 299 | }; 300 | 301 | cursorUp(wrap) { 302 | if(this.maxItems() === 1) return; 303 | 304 | let newIndex = null; 305 | if(this.index() == 0 && wrap) { 306 | this.select(this.maxItems() - 1); 307 | } 308 | else { 309 | this.select(this.index()-1); 310 | } 311 | }; 312 | 313 | cursorRight() { 314 | if(this.rotate) { 315 | this._data[this.index()].rotate(1); 316 | this.refresh(); 317 | } 318 | }; 319 | 320 | cursorLeft() { 321 | if(this.rotate) { 322 | this._data[this.index()].rotate(-1); 323 | this.refresh(); 324 | } 325 | } 326 | } 327 | 328 | Kru.helpers.windowHandlers['piecelist'] = Kru_PipeGame_PieceListWindow; 329 | 330 | class Kru_PipeGame_GridWindow extends Kru_GenericListWindow { 331 | 332 | initialize(win) { 333 | this.dim = win.dim || [6,6]; 334 | 335 | this._lineHeight = win.icon.height; 336 | 337 | this._data = Array(this.dim[0] * this.dim[1]); 338 | this._data.fill(null); 339 | 340 | this._margin = win.margin || 3; 341 | this.offset = win.offset || [win.icon.width+(this._margin*2), this._margin*2]; 342 | 343 | let goalCount = win.goals || 1; 344 | 345 | this.lineColor = win.lineColor || '#aaaaaa'; 346 | 347 | this._goals = [ 348 | this.getGoals(goalCount), 349 | this.getGoals(goalCount) 350 | ]; 351 | 352 | this.goalConnected = Array(goalCount); 353 | this.goalConnected.fill(false); 354 | 355 | super.initialize(win); 356 | this._index = 0; 357 | 358 | // Set event handlers. 359 | this.setHandler('ok', this.onOk.bind(this)); 360 | this.setHandler('cancel', this.onCancel.bind(this)); 361 | 362 | Object.defineProperty(this, '__index', { 363 | get: function () { 364 | return this.__ItoXY(this._index); 365 | }, 366 | set: function (xy) { 367 | this._index = this.__XYtoI(xy); 368 | return xy; 369 | } 370 | }); 371 | } 372 | 373 | // Index to [X,Y] 374 | __ItoXY(index) { 375 | return [index % this.dim[0], Math.floor(index / this.dim[0])]; 376 | } 377 | 378 | // [X,Y] to Index 379 | __XYtoI(xy) { 380 | return xy[0] + (xy[1] * this.dim[0]); 381 | } 382 | 383 | __data(xy, value) { 384 | let index = this.__XYtoI(xy); 385 | if(typeof value === 'undefined') { 386 | return this._data[index]; 387 | } 388 | else { 389 | return this._data[index] = value; 390 | } 391 | } 392 | 393 | position(index) { 394 | let pos = this.__ItoXY(index); 395 | return [ 396 | (pos[0] * (this._iconWidth + this._margin)) + this.offset[0], 397 | (pos[1] * (this._iconHeight + this._margin)) + this.offset[1] 398 | ]; 399 | } 400 | 401 | maxCols() { 402 | return this.dim[0]; 403 | } 404 | 405 | maxItems() { 406 | return this.dim[0] * this.dim[1]; 407 | } 408 | 409 | itemRect(index) { 410 | let rect = new Rectangle(); 411 | let pos = this.position(index); 412 | 413 | rect.x = pos[0] - this._margin; 414 | rect.y = pos[1] - this._margin; 415 | rect.width = this._iconWidth + (this._margin * 2); 416 | rect.height = this._iconHeight + (this._margin * 2); 417 | 418 | return rect; 419 | } 420 | 421 | drawItem(index) { 422 | let content = this._data[index]; 423 | if(content) { 424 | let piece = this._data[index]; 425 | let pos = this.position(index); 426 | 427 | this.drawIconIndex(piece.img[0], piece.img[1], pos[0], pos[1], piece.rotation); 428 | } 429 | } 430 | 431 | drawGrid() { 432 | let off = Math.round(this._margin / 2); 433 | 434 | let min = this.offset; 435 | let max = this.position((this.dim[0] * (this.dim[1]+1)) - 1); 436 | max[0] += this._iconWidth; 437 | 438 | // vertical 439 | for(let i = 0; i <= this.dim[0]; i++) { 440 | let x = (i * (this._iconWidth + this._margin)) + this.offset[0]-off; 441 | this.contents.kDrawLine(x, min[1]-off, x, max[1]-off, this.lineColor, 2); 442 | } 443 | // horizontal 444 | for(let i = 0; i <= this.dim[1]; i++) { 445 | let y = (i * (this._iconHeight + this._margin)) + this.offset[1]-off; 446 | this.contents.kDrawLine(min[0]-off, y, max[0]+off, y, this.lineColor, 2); 447 | } 448 | 449 | } 450 | 451 | async drawStartAndEnd() { 452 | for(let i = 0; i < this._goals[0].length; i++) { 453 | let startX = 0; 454 | let startY = (this._goals[0][i] * (this._iconHeight + this._margin)) + this.offset[1]; 455 | this.drawIconIndex(4, 1, startX, startY); 456 | } 457 | for(let i = 0; i < this._goals[1].length; i++) { 458 | let endY = (this._goals[1][i] * (this._iconHeight + this._margin)) + this.offset[1]; 459 | let endX = (this.dim[0] * (this._iconWidth + this._margin)) + this.offset[0]; 460 | this.drawIconIndex(5, 0 + this.goalConnected[i], endX, endY); 461 | } 462 | } 463 | 464 | getGoals(count) { 465 | let goals = []; 466 | do { 467 | let val = Math.floor(Math.random() * this.dim[1]); 468 | if(goals.indexOf(val) === -1) { 469 | goals.push(val); 470 | } 471 | } while( goals.length < count); 472 | return goals; 473 | } 474 | 475 | refresh() { 476 | this.contents.clear(); 477 | this.drawGrid(); 478 | this.drawStartAndEnd(); 479 | this.drawAllItems(); 480 | } 481 | 482 | onCancel() { 483 | this.deactivate(); 484 | this.pieceWindow.activate(); 485 | } 486 | 487 | onOk() { 488 | if(this._data[this._index] === null) { 489 | let args = this.pieceWindow.use(); 490 | args = Object.assign(args, { 491 | index: this._index, 492 | dim: this.dim 493 | }); 494 | 495 | let piece = new Piece(args); 496 | 497 | this._data[this._index] = piece; 498 | 499 | this.playOkSound(); 500 | 501 | this.checkActives(piece); 502 | this.activateNeighbors(piece); 503 | 504 | this.refresh(); 505 | 506 | if(this.checkComplete()) { 507 | // Do win. 508 | this.doSuccess(); 509 | } 510 | 511 | 512 | if(this.pieceWindow.pieces > 1 || this.pieceWindow.rotate) { 513 | this.deactivate(); 514 | this.pieceWindow.activate(); 515 | } 516 | else { 517 | this.activate(); 518 | } 519 | } 520 | else { 521 | this.playBuzzerSound(); 522 | this.activate(); 523 | } 524 | } 525 | 526 | doSuccess() { 527 | // TODO: add a little message or something. 528 | $gameTemp[Kru.PM.params['Variable']] = true; 529 | this._win.scene.popScene(); 530 | } 531 | 532 | 533 | checkActives(piece) { 534 | // Check for the start point. 535 | if(piece.x === 0) { 536 | for(let i = 0; i < this._goals[0].length; i++) { 537 | if(this._goals[0][i] == piece.y) { 538 | piece.active = true; 539 | break; 540 | } 541 | } 542 | } 543 | 544 | let neighbors = piece.neighbors(); 545 | if(!piece.active) { 546 | for(let i = 0; i < neighbors.length; i++) { 547 | if(typeof neighbors[i] == 'undefined') continue; 548 | let neighbor = this._data[neighbors[i]]; 549 | 550 | if(neighbor && neighbor.active && neighbor.opSide(i)) { 551 | piece.active = true; 552 | } 553 | } 554 | } 555 | } 556 | 557 | activateNeighbors(piece) { 558 | if(piece.active) { 559 | let neighbors = piece.neighbors(); 560 | for(let i = 0; i < neighbors.length; i++) { 561 | let neighbor = this._data[neighbors[i]]; 562 | 563 | if(neighbor && !neighbor.active && neighbor.opSide(i)) { 564 | neighbor.active = true; 565 | this.activateNeighbors(neighbor); 566 | } 567 | } 568 | } 569 | } 570 | 571 | checkComplete() { 572 | let actives = 0; 573 | for(let i = 0; i < this._goals[1].length; i++) { 574 | let index = this.__XYtoI([this.dim[0]-1, this._goals[1][i]]); 575 | let piece = this._data[index]; 576 | 577 | if(piece && piece.side(1) && piece.active) { 578 | actives++; 579 | this.goalConnected[i] = true; 580 | } 581 | } 582 | 583 | return actives == this._goals[1].length; 584 | } 585 | } 586 | 587 | Kru.helpers.windowHandlers['gamegrid'] = Kru_PipeGame_GridWindow; 588 | 589 | Kru.PM.pieces = {}; 590 | class Piece { 591 | 592 | constructor(options) { 593 | this.direction = 0; 594 | this.index = null; 595 | this.dim = [null, null]; 596 | // 0 597 | // 3 1 598 | // 2 599 | // this.connections = []; 600 | // this._img = null; 601 | 602 | this.active = false; 603 | 604 | 605 | for(name in options) { 606 | this[name] = options[name]; 607 | } 608 | 609 | Object.defineProperty(this, 'img', { 610 | get: function () { return [this._img, 0+this.active] } 611 | }); 612 | 613 | Object.defineProperty(this, 'rotation', { 614 | get: function () { return this.direction * 90 } 615 | }); 616 | 617 | Object.defineProperty(this, 'x', { 618 | get: function () { return this.index % this.dim[0]; } 619 | }); 620 | Object.defineProperty(this, 'y', { 621 | get: function () { return Math.floor(this.index / this.dim[0]); } 622 | }); 623 | 624 | Object.defineProperty(this, 'xy', { 625 | get: function () { 626 | return [this.x, this.y]; 627 | } 628 | }); 629 | } 630 | 631 | rotate(n) { 632 | if(typeof n === 'undefined') { 633 | n = 1; 634 | } 635 | 636 | let d = (this.direction + n) % this.connections.length;; 637 | 638 | if(d < 0) { 639 | d = this.connections.length + n ; 640 | } 641 | 642 | this.direction = d; 643 | } 644 | 645 | // Is there a connection on the given side? 646 | side(side) { 647 | // Take our given side, subtract our rotation (direction), add the maximum 648 | // number of sides so this can't possibly be negative, and then return the 649 | // modulo. 650 | let n = (side + this.connections.length - this.direction) % this.connections.length; 651 | return this.connections[n]; 652 | } 653 | 654 | // Is there a connection on the opposite side? 655 | opSide(side) { 656 | // Take our given side, subtract our rotation (direction), add the maximum 657 | // number of sides so this can't possibly be negative, add half again our 658 | // number of sides to do a 180 rotation, and then return the modulo. 659 | let n = (side + this.connections.length - this.direction + Math.floor(this.connections.length / 2)) 660 | % this.connections.length; 661 | return this.connections[n]; 662 | } 663 | 664 | 665 | sideName(side) { 666 | switch (side) { 667 | case 0: return 'up'; 668 | case 1: return 'right'; 669 | case 2: return 'down'; 670 | case 3: return 'left'; 671 | } 672 | } 673 | 674 | // Index to [X,Y] 675 | __ItoXY(index) { 676 | return [index % this.dim[0], Math.floor(index / this.dim[0])]; 677 | } 678 | 679 | // [X,Y] to Index 680 | __XYtoI(xy) { 681 | return xy[0] + (xy[1] * this.dim[0]); 682 | } 683 | 684 | up(n) { 685 | n = n || 1; 686 | if(this.side(0) && this.y - n >= 0) { 687 | return this.__XYtoI([this.x, this.y - n]); 688 | } 689 | } 690 | 691 | right(n) { 692 | n = n || 1; 693 | if(this.side(1) && this.x + n <= this.dim[0]) { 694 | return this.__XYtoI([this.x + n, this.y]); 695 | } 696 | } 697 | 698 | down(n) { 699 | n = n || 1; 700 | if(this.side(2) && this.y + n <= this.dim[1]) { 701 | return this.__XYtoI([this.x, this.y + n]); 702 | } 703 | } 704 | 705 | left(n) { 706 | n = n || 1; 707 | if(this.side(3) && this.x - n >= 0) { 708 | return this.__XYtoI([this.x - n, this.y]); 709 | } 710 | } 711 | 712 | neighbor(side, n) { 713 | switch(side) { 714 | case 0: return this.up(n); 715 | case 1: return this.right(n); 716 | case 2: return this.down(n); 717 | case 3: return this.left(n); 718 | } 719 | } 720 | 721 | neighbors() { 722 | let neighbors = []; 723 | for(let i = 0; i < this.connections.length; i++) { 724 | if(this.side(i)) { 725 | neighbors[i] = this.neighbor(i); 726 | } 727 | } 728 | return neighbors; 729 | } 730 | } 731 | 732 | class PieceX extends Piece { 733 | constructor() { 734 | super(); 735 | this.name = 'X'; 736 | this._img = 2; 737 | this.connections = [true, true, true, true]; 738 | } 739 | } 740 | Kru.PM.pieces['PieceX'] = PieceX; 741 | 742 | class PieceT extends Piece { 743 | constructor() { 744 | super(); 745 | this.name = 'T'; 746 | this._img = 3; 747 | this.connections = [true, true, false, true]; 748 | } 749 | } 750 | Kru.PM.pieces['PieceT'] = PieceT; 751 | 752 | class PieceI extends Piece { 753 | constructor() { 754 | super(); 755 | this.name = 'I'; 756 | this._img = 0; 757 | this.connections = [true, false, true, false] 758 | } 759 | } 760 | Kru.PM.pieces['PieceI'] = PieceI; 761 | 762 | class PieceL extends Piece { 763 | constructor() { 764 | super(); 765 | this.name = 'L'; 766 | this._img = 1; 767 | this.connections = [true, true, false, false] 768 | } 769 | } 770 | Kru.PM.pieces['PieceL'] = PieceL; -------------------------------------------------------------------------------- /Kru_PreviousPosition.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Kru_PreviousPosition.js 3 | //============================================================================= 4 | 5 | /*: 6 | * @plugindesc Stores the player's position and can return the player there. 7 | * @author Krusynth 8 | * 9 | * @help 10 | * 11 | * Usage: Before running a transfer within an event, run this custom script to 12 | * store the current location: Kru.PP.store(); 13 | * 14 | * To return to that location, run Kru.PP.recall(); You may automatically 15 | * change the direction of the player by passing it as an argument. 16 | */ 17 | 18 | var Kru = Kru || {}; 19 | Kru.PP = { 20 | location: {} 21 | }; 22 | 23 | Kru.PP.store = function() { 24 | this.location = { 25 | map: $gameMap.mapId(), 26 | x: $gamePlayer._x, 27 | y: $gamePlayer._y, 28 | d: $gamePlayer.direction 29 | }; 30 | } 31 | 32 | Kru.PP.transfer = function(map, x, y, d, fade) { 33 | fade = fade || 0; 34 | if(map != null) { 35 | $gamePlayer.reserveTransfer(map, x, y, d, fade); 36 | } 37 | } 38 | 39 | Kru.PP.recall = function(d, fade) { 40 | d = d || this.location.d; 41 | Kru.PP.transfer( 42 | this.location.map, 43 | this.location.x, 44 | this.location.y, 45 | d, 46 | fade 47 | ); 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Kru_Reputation.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Reputation 3 | // Version: 1.0.1 4 | //============================================================================= 5 | /*: 6 | * @plugindesc v1.0.1 Reputation system 7 | * 8 | * @author Krusynth 9 | * 10 | * @help 11 | * ============================================================================ 12 | * Information 13 | * ============================================================================ 14 | * 15 | * Keeps track of your reputation with various factions & friends. 16 | * 17 | * Note: for convenience of management, you'll need to create a Variable for 18 | * each faction that you're keeping track of. These must be named like so: 19 | * KruRep:Your Group Name 20 | * 21 | * To increase or decrease your character's reputation, just increase the value 22 | * of the variable. 23 | * 24 | * You can give discounts at shops by running this script before 'Shop Processing': 25 | * KruFactionDiscountPrice('Faction Name', 'Known', '-10%'); // To use a percentage 26 | * KruFactionDiscountPrice('Faction Name', 'Known', -20); // For a flat amount 27 | * 28 | * You can also increase your character's sell price from the default (505) at 29 | * these shops with: 30 | * KruFactionSellBonus('Famous', '20%'); // To use a percentage 31 | * KruFactionSellBonus('Famous', 30); // For a flat amount 32 | * 33 | * @param Menu Name 34 | * @desc The name of the menu item to look at your faction status. 35 | * @default Factions 36 | * 37 | * @param Reputation Levels 38 | * @desc Names for different reputation levels. 39 | * @default Despised:-100, Hated:-50, Unknown:0, Familiar:50, Known:100 40 | * 41 | * @param Show Unknown Factions 42 | * @desc Show factions that haven't been discovered yet on the menu? 43 | * @type boolean 44 | * @on Yes 45 | * @off No 46 | * @default true 47 | * 48 | * @param Icons 49 | * @desc Name of the icon file to use, in img/system, without the file extension. 50 | * @type file 51 | * @dir img/system 52 | * 53 | * @param Icon Size 54 | * @parent Icons 55 | * @type number 56 | * @desc Size of the icons to use. 57 | * @default 32 58 | * 59 | * @param Custom Icons 60 | * @parent Icons 61 | * @desc By default, the icons will be determined by their order in the variables. This option allows you to override the default. 62 | * @type struct[] 63 | * 64 | * Terms & Conditions 65 | * This plugin is free for non-commercial and commercial use. 66 | */ 67 | 68 | /*~struct~CustomIcon: 69 | * @param Faction 70 | * @type variable 71 | * 72 | * @param Icon 73 | * @desc The index of the icon in the icon file. 0 is the first icon, etc. 74 | * @type number 75 | */ 76 | 77 | /* 78 | * TODO: 79 | * Set factions in Map notes. 80 | */ 81 | 82 | var Imported = Imported || {}; 83 | Imported.Kru_Reputation = "1.0.1"; 84 | 85 | var Kru = Kru || {}; 86 | 87 | if(!Imported.Kru_Core) { 88 | alert("Kru_Reputation requires Kru_Core."); 89 | throw new Error("Kru_Reputation requires Kru_Core."); 90 | } 91 | 92 | Kru.RP = { 93 | config: {}, 94 | factions: [], 95 | factionMap: {}, 96 | prefix: 'KruRep:' 97 | }; 98 | 99 | Kru.RP.Parameters = PluginManager.parameters('Kru_Reputation'); 100 | Kru.RP.Parameters['Show Unknown Factions'] = ( 101 | Kru.RP.Parameters['Show Unknown Factions'].toLowerCase() === 'true' 102 | ); 103 | Kru.RP.Parameters['Icon Size'] = parseInt(Kru.RP.Parameters['Icon Size']); 104 | // Preload our images. 105 | if(Kru.RP.Parameters['Icons']) { 106 | ImageManager.loadSystem(Kru.RP.Parameters['Icons']); 107 | } 108 | 109 | // Transmogrifying a list of integers into something usable in Javascript is 110 | // hard. We build a wrapper class to handle all the sorting and type mangling. 111 | function ReputationLevels(levels) { 112 | this.values = []; 113 | this.levels = {}; 114 | this.levelsLookup = {}; 115 | 116 | this.init = function(levels) { 117 | let tmpLevels = levels.split(',').reduce(function(obj, value) { 118 | [name, value] = value.trim().split(':'); 119 | if(name.length && value.length) { 120 | obj[value.trim()] = name.trim(); 121 | } 122 | return obj; 123 | }, {}); 124 | 125 | this.values = Object.keys(tmpLevels) 126 | .sort(function(a, b) { 127 | if(parseInt(a) < parseInt(b)) { 128 | return -1; 129 | } 130 | else if(parseInt(a) > parseInt(b)) { 131 | return 1; 132 | } 133 | return 0; 134 | }) 135 | .map(function(val) { return parseInt(val); }); 136 | 137 | for(let i = 0; i < this.values.length; i++) { 138 | let value = this.values[i]; 139 | let name = tmpLevels[this.values[i]]; 140 | this.levels[value] = name; 141 | this.levelsLookup[name] = value; 142 | } 143 | } 144 | 145 | this.getLevel = function(value) { 146 | let level = this.levels[ this.values[0] ]; 147 | for(i = 0; i < this.values.length; i++) { 148 | if(value >= this.values[i]) { 149 | level = this.levels[ this.values[i] ]; 150 | } 151 | } 152 | return level; 153 | } 154 | 155 | this.getValue = function(value) { 156 | return this.levelsLookup[value]; 157 | } 158 | 159 | this.init(levels); 160 | } 161 | 162 | Kru.RP.levels = 163 | new ReputationLevels(Kru.RP.Parameters['Reputation Levels']); 164 | 165 | if(!Imported.Kru_Core) { 166 | alert("Kru_SkillTree requires Kru_Core."); 167 | throw new Error("Kru_SkillTree requires Kru_Core."); 168 | } 169 | 170 | /* 171 | * Setup our factions. 172 | */ 173 | 174 | Kru.helpers.addEvent('$dataSystem', loadFactions); 175 | 176 | function loadFactions(obj, name) { 177 | if(Kru.RP.factions.length) { 178 | return; 179 | } 180 | 181 | // Store our factions. 182 | for(let i = 0; i < $dataSystem.variables.length; i++) { 183 | if($dataSystem.variables[i].substr(0, Kru.RP.prefix.length) == Kru.RP.prefix) { 184 | [trash, name] = $dataSystem.variables[i].split(':'); 185 | Kru.RP.factions.push(name.trim()); 186 | Kru.RP.factionMap[name.trim()] = i; 187 | } 188 | } 189 | }; 190 | 191 | Kru.RP.factionValue = function(name) { 192 | return $gameVariables._data[Kru.RP.factionMap[name]]; 193 | } 194 | 195 | /* 196 | * Add our menu item. 197 | */ 198 | 199 | Kru.RP.Window_MenuCommand__addMainCommands = Window_MenuCommand.prototype.addMainCommands; 200 | 201 | Window_MenuCommand.prototype.addMainCommands = function() { 202 | Kru.RP.Window_MenuCommand__addMainCommands.call(this); 203 | 204 | this.addCommand(Kru.RP.Parameters['Menu Name'], 'factions', true); 205 | }; 206 | 207 | Kru.RP.Scene_Menu__createCommandWindow = Scene_Menu.prototype.createCommandWindow; 208 | 209 | Scene_Menu.prototype.createCommandWindow = function() { 210 | Kru.RP.Scene_Menu__createCommandWindow.call(this); 211 | this._commandWindow.setHandler('factions', this.commandFactions.bind(this)); 212 | } 213 | 214 | Scene_Menu.prototype.commandFactions = function() { 215 | SceneManager.push(Scene_Factions); 216 | } 217 | 218 | function Scene_Factions() { 219 | this.initialize.apply(this, arguments); 220 | } 221 | 222 | Scene_Factions.prototype = Object.create(Scene_MenuBase.prototype); 223 | Scene_Factions.prototype.constructor = Scene_Factions; 224 | 225 | Scene_Factions.prototype.create = function(){ 226 | Scene_MenuBase.prototype.create.call(this); 227 | 228 | this.wm = new Kru.helpers.WindowManager(this); 229 | 230 | this.wm.addWindow({ 231 | width: 1, 232 | height: 0.11, 233 | content: Kru.RP.Parameters['Menu Name'] 234 | }) 235 | 236 | let factions = []; 237 | for(let i = 0; i < Kru.RP.factions.length; i++) { 238 | let value = Kru.RP.factionValue(Kru.RP.factions[i]); 239 | 240 | if( 241 | Kru.RP.Parameters['Show Unknown Factions'] || 242 | typeof value !== 'undefined' 243 | ) { 244 | value = value || 0; 245 | factions.push({ 246 | name: Kru.RP.factions[i], 247 | value: value, 248 | rank: Kru.RP.levels.getLevel(value), 249 | index: i 250 | }); 251 | } 252 | } 253 | 254 | let winOptions = { 255 | width: 1, 256 | height: 0.89, 257 | type: 'faction', 258 | content: factions, 259 | icon: { 260 | set: Kru.RP.Parameters['Icons'], 261 | width: Kru.RP.Parameters['Icon Size'], 262 | height: Kru.RP.Parameters['Icon Size'] 263 | } 264 | }; 265 | 266 | if(Kru.RP.Parameters['Icons']) { 267 | winOptions['lineHeight'] = Kru.RP.Parameters['Icon Size']+4; 268 | 269 | // The text height is 32px, so we need to bump this up if the icons are smaller. 270 | if(winOptions['lineHeight'] < 32) { 271 | winOptions['lineHeight'] = 32; 272 | } 273 | } 274 | 275 | let factionWin = this.wm.addWindow(winOptions); 276 | 277 | factionWin.activate(); 278 | } 279 | 280 | function Kru_FactionWindow() { 281 | this.initialize.apply(this, arguments); 282 | }; 283 | 284 | Kru_FactionWindow.prototype = Object.create(Kru_GenericListWindow.prototype); 285 | 286 | Kru_FactionWindow.prototype.initialize = function(win) { 287 | Kru_GenericListWindow.prototype.initialize.call(this, win); 288 | 289 | // Set event handlers. 290 | this.setHandler('cancel', this.onCancel.bind(this)); 291 | } 292 | 293 | Kru_FactionWindow.prototype.onCancel = function() { 294 | this._win.scene.popScene(); 295 | }; 296 | 297 | Kru_FactionWindow.prototype.drawItem = function(index) { 298 | var content = this._data[index]; 299 | var yOffset = this.lineHeight() * index; 300 | 301 | if(Kru.RP.Parameters['Icons']) { 302 | let item = { 303 | name: content.name, 304 | iconIndex: index 305 | }; 306 | this.drawItemName(item, 0, yOffset, this._win._w); 307 | } 308 | else { 309 | this.drawText(content.name, 0, yOffset, this._win._w); 310 | } 311 | 312 | let color = 3; 313 | if(content.value < 0) { 314 | color = 2; 315 | } 316 | 317 | // Width is window width minus 2 * standardPadding 318 | let width = this._win._w - (2 * this.standardPadding()); 319 | let rankText = content.rank+' ('+content.value+')'; 320 | 321 | this.changeTextColor(this.textColor(color)); 322 | this.drawText(rankText, 0, yOffset, width, 'right'); 323 | this.resetTextColor(); 324 | }; 325 | Kru.helpers.windowHandlers['faction'] = Kru_FactionWindow; 326 | 327 | /* 328 | * Allow faction discounts or make more expensive 329 | */ 330 | KruSetFaction = function(factionName) { 331 | if($gameMap._interpreter._eventId) { 332 | $gameMap._events[$gameMap._interpreter._eventId]._faction = factionName; 333 | } 334 | else { 335 | $gameMap._faction = factionName; 336 | } 337 | } 338 | 339 | Kru.RP.__processFactionDiscountArgs = function(args) { 340 | let faction, level, discount; 341 | if(args.length == 3) { 342 | [faction, level, discount] = args; 343 | } 344 | else if(args.length == 2) { 345 | [level, discount] = args; 346 | faction = $gameMap._events[$gameMap._interpreter._eventId]._faction || 347 | $gameMap._faction; 348 | 349 | } 350 | 351 | if(!Number.isInteger(level)){ 352 | if(/^[0-9]+$/.test(level)) { 353 | level = parseInt(level); 354 | } 355 | else { 356 | level = Kru.RP.levels.getValue(level); 357 | } 358 | } 359 | 360 | return [faction, level, discount]; 361 | } 362 | 363 | Kru.RP.__adjustPrice = function(price, adjustment) { 364 | if(adjustment) { 365 | if(/^-?[0-9.]+%$/.test(adjustment)) { 366 | let tmpDiscount = 1 + (Number(adjustment.substr(0, adjustment.length -1)) / 100) 367 | price = price * tmpDiscount; 368 | } 369 | else { 370 | price = price + Number(adjustment); 371 | } 372 | } 373 | return price; 374 | } 375 | 376 | // Usage: 377 | // KruFactionDiscountPrice('Faction Name', 'Known', '-10%'); 378 | // KruFactionDiscountPrice('Famous', -20); 379 | KruFactionDiscountPrice = function() { 380 | [faction, level, discount] = Kru.RP.__processFactionDiscountArgs(arguments); 381 | 382 | if(faction && Kru.RP.factionValue(faction) >= level) { 383 | $gameMap._events[$gameMap._interpreter._eventId]._discount = discount; 384 | } 385 | } 386 | 387 | Kru.RP.Window_ShopBuy__price = Window_ShopBuy.prototype.price; 388 | Window_ShopBuy.prototype.price = function(item) { 389 | let price = Kru.RP.Window_ShopBuy__price.call(this, item); 390 | let discount = $gameMap._events[$gameMap._interpreter._eventId]._discount; 391 | return Kru.RP.__adjustPrice(price, discount); 392 | }; 393 | 394 | Kru.RP.Scene_Shop__create = Scene_Shop.prototype.create; 395 | Scene_Shop.prototype.create = function() { 396 | Kru.RP.Scene_Shop__create.call(this); 397 | if($gameMap._events[$gameMap._interpreter._eventId]._discount) { 398 | this._helpWindow.setText('We\'ve got special prices for friends.'); 399 | } 400 | } 401 | 402 | // Usage: 403 | // KruFactionSellBonus('Faction Name', 'Known', '10%'); 404 | // KruFactionSellBonus('Famous', 20); 405 | KruFactionSellBonus = function() { 406 | [faction, level, bonus] = Kru.RP.__processFactionDiscountArgs(arguments); 407 | if(faction && Kru.RP.factionValue(faction) > level) { 408 | $gameMap._events[$gameMap._interpreter._eventId]._sellBonus = bonus; 409 | } 410 | } 411 | 412 | Kru.RP.Scene_Shop__sellingPrice = Scene_Shop.prototype.sellingPrice; 413 | Scene_Shop.prototype.sellingPrice = function() { 414 | let price = Kru.RP.Scene_Shop__sellingPrice.call(this); 415 | let bonus = $gameMap._events[$gameMap._interpreter._eventId]._sellBonus; 416 | return Kru.RP.__adjustPrice(price, bonus); 417 | }; -------------------------------------------------------------------------------- /Kru_SRD_FaceImages.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Kru_SRD_FaceImages.js 3 | //============================================================================= 4 | 5 | /*: 6 | * @plugindesc Overrides the bust images of the SRC menu plugin. 7 | * @author Krusynth 8 | * 9 | * @help Defaults to img/faces/filename 10 | */ 11 | 12 | Window_MenuStatus.prototype.drawBust = function(actor, rect, xOff, yOff) { 13 | // var bitmap = ImageManager.loadSumRndmDdeMB(actor.actor().ams_bs_bust); 14 | // var sx = bitmap.width / 2 - this.itemWidth() / 2; 15 | // this.contents.blt(bitmap, sx, sy, sw, sh, dx, dy); 16 | // this.contents.blt(bitmap, sx, 0, this.itemWidth(), bitmap.height, rect.x + xOff, (rect.height - bitmap.height) + yOff); 17 | this.drawFace(actor.faceName(), actor.faceIndex(), rect.x + xOff, yOff-80, this.itemWidth(), rect.height); 18 | // console.log('drawBust', actor.faceName(), actor.faceIndex(), xOff, yOff, this.itemWidth(), rect.height); 19 | }; -------------------------------------------------------------------------------- /Kru_SkillCore.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Krusynth Skill Core 3 | // Version: 1.0.0 4 | //============================================================================= 5 | /*: 6 | * @plugindesc Shared base for Krusynth skill-related plugins 7 | * 8 | * @author Krusynth 9 | * 10 | * @param ---General--- 11 | * @default 12 | * 13 | * @help 14 | * ============================================================================ 15 | * Information 16 | * ============================================================================ 17 | * 18 | * This is the base include for many Krusynth RPG Maker MV skill plugins. It 19 | * extends the core engine for better skill cost calculations. Skills can now 20 | * have an HP cost as well. 21 | */ 22 | 23 | var Imported = Imported || {}; 24 | Imported.Kru_SkillCore = "1.0.0"; 25 | 26 | var Kru = Kru || {}; 27 | Kru.SC = {}; 28 | 29 | // Cost adjustment 30 | Kru.SC.Game_BattlerBase___paySkillCost = Game_BattlerBase.prototype.paySkillCost; 31 | Game_BattlerBase.prototype.paySkillCost = function(skill) { 32 | this._hp -= this.skillHpCost(skill); 33 | this._mp -= this.skillMpCost(skill); 34 | this._tp -= this.skillTpCost(skill); 35 | // TODO: allow any arbitrary cost in skill meta. 36 | }; 37 | 38 | Game_BattlerBase.prototype.canPaySkillCost = function(skill) { 39 | return this._tp >= this.skillTpCost(skill) && 40 | this._mp >= this.skillMpCost(skill) && 41 | this._hp >= this.skillHpCost(skill); 42 | }; 43 | 44 | Kru.SC.Game_BattlerBase___skillMpCost = Game_BattlerBase.prototype.skillMpCost; 45 | Game_BattlerBase.prototype.skillMpCost = function(item) { 46 | let cost = Kru.SC.Game_BattlerBase___skillMpCost.call(this, item); 47 | let skill = this._stskills[item.id]; 48 | 49 | if(item.meta.cost && item.meta.cost.mp) { 50 | let a = this; 51 | eval(item.meta.cost.mp); 52 | } 53 | return cost; 54 | }; 55 | 56 | Kru.SC.Game_BattlerBase___skillTpCost = Game_BattlerBase.prototype.skillTpCost; 57 | Game_BattlerBase.prototype.skillTpCost = function(item) { 58 | let cost = Kru.SC.Game_BattlerBase___skillTpCost.call(this, item); 59 | let a = this; 60 | if(item.meta.cost && item.meta.cost.tp) { 61 | eval(item.meta.cost.tp); 62 | } 63 | return cost; 64 | }; 65 | 66 | // This doesn't exist in the core engine. 67 | Game_BattlerBase.prototype.skillHpCost = function(item) { 68 | let cost = item.hpCost || 0; 69 | if(item.meta.cost && item.meta.cost.hp) { 70 | eval(item.meta.cost.hp); 71 | } 72 | return cost; 73 | }; 74 | -------------------------------------------------------------------------------- /Kru_SkillToggle.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Skill Toggle 3 | // Version: 1.0.0 4 | //============================================================================= 5 | /*: 6 | * @plugindesc Creates passive skills that can be toggled on/off. 7 | * 8 | * @author Krusynth 9 | * 10 | * @help 11 | * ============================================================================ 12 | * Information 13 | * ============================================================================ 14 | * 15 | * Creates passive skills that can be toggled on/off. 16 | * 17 | * Terms & Conditions 18 | * This plugin is free for non-commercial and commercial use. 19 | */ 20 | 21 | /* 22 | * TODO 23 | * - Refresh reserve after adding points to skills. 24 | */ 25 | var Imported = Imported || {}; 26 | Imported.Kru_SkillToggle = "1.0.0"; 27 | 28 | var Kru = Kru || {}; 29 | Kru.STog = {}; 30 | 31 | if(!Imported.Kru_Core) { 32 | alert("Kru_SkillToggle requires Kru_Core."); 33 | throw new Error("Kru_SkillToggle requires Kru_Core."); 34 | } 35 | 36 | if(!Imported.Kru_SkillCore) { 37 | alert("Kru_SkillToggle requires Kru_SkillCore."); 38 | throw new Error("Kru_SkillToggle requires Kru_SkillCore."); 39 | } 40 | 41 | Kru.STog.Window_SkillList_drawItem = Window_SkillList.prototype.drawItem; 42 | Window_SkillList.prototype.drawItem = function(index) { 43 | var skill = this._data[index]; 44 | if (skill) { 45 | var costWidth = this.costWidth(); 46 | var rect = this.itemRect(index); 47 | rect.width -= this.textPadding(); 48 | this.changePaintOpacity(this.isEnabled(skill)); 49 | this.drawItemName(skill, rect.x, rect.y, rect.width - costWidth); 50 | this.drawSkillCost(skill, rect.x, rect.y, rect.width); 51 | this.changePaintOpacity(1); 52 | } 53 | }; 54 | 55 | Kru.STog.Window_SkillList___drawItemName = Window_SkillList.prototype.drawItemName; 56 | Window_SkillList.prototype.drawItemName = function(item, x, y, width) { 57 | width = width || 312; 58 | if (item) { 59 | var iconBoxWidth = Window_Base._iconWidth + 4; 60 | 61 | this.resetTextColor(); 62 | if(item.meta && item.meta.type) { 63 | if(item.meta.type == 'toggle') { 64 | if(this._actor._stskills[item.id].toggleState == true) { 65 | this.changeTextColor(this.textColor(23)); 66 | } 67 | else { 68 | this.changeTextColor(this.textColor(22)); 69 | } 70 | } 71 | } 72 | this.drawIcon(item.iconIndex, x + 2, y + 2); 73 | this.drawText(item.name, x + iconBoxWidth, y, width - iconBoxWidth); 74 | } 75 | }; 76 | 77 | Kru.STog.setHelpWindowItem = Window_SkillList.prototype.setHelpWindowItem; 78 | Window_SkillList.prototype.setHelpWindowItem = function(item) { 79 | this._helpWindow.contents.clear(); 80 | this._helpWindow.setText(''); 81 | Kru.STog.setHelpWindowItem.call(this, item); 82 | 83 | // If this skill is toggleable we need to show the state in the help. 84 | let msg; 85 | if (this._helpWindow && item) { 86 | if(item.meta && item.meta.type) { 87 | if(item.meta.type == 'toggle') { 88 | if(this._actor._stskills[item.id].toggleState == true) { 89 | msg = '[ACTIVE]'; 90 | this._helpWindow.changeTextColor(this.textColor(23)); 91 | 92 | } 93 | else { 94 | msg = '[INACTIVE]'; 95 | this._helpWindow.changeTextColor(this.textColor(22)); 96 | } 97 | } 98 | } 99 | 100 | if(msg) { 101 | this._helpWindow.drawText(msg, 0, 32, Graphics.boxWidth - this.padding*2, 'right') 102 | } 103 | this.resetTextColor(); 104 | } 105 | }; 106 | 107 | Kru.STog.Window_SkillList___isCurrentItemEnabled = Window_SkillList.prototype.isCurrentItemEnabled; 108 | Window_SkillList.prototype.isCurrentItemEnabled = function() { 109 | let result = Kru.STog.Window_SkillList___isCurrentItemEnabled.call(this); 110 | let item = this.item(); 111 | if(!result && item && item.meta && item.meta.type) { 112 | if(item.meta.type == 'toggle') { 113 | result = true; 114 | } 115 | } 116 | return result; 117 | } 118 | 119 | // Create method to calculate reserved points. 120 | Kru.STog.Game_Battler___refresh = Game_Battler.prototype.refresh; 121 | 122 | Kru.STog.Game_BattlerBase___initialize = Game_BattlerBase.prototype.initialize; 123 | Game_BattlerBase.prototype.initialize = function() { 124 | Kru.STog.Game_BattlerBase___initialize.call(this); 125 | this.resetReserve(); 126 | this._stskills = this._stskills || []; 127 | this._mtp = this._mtp || 100; 128 | this._tp = this._tp || 0; 129 | } 130 | 131 | Game_BattlerBase.prototype.maxTp = function() { 132 | return this._mtp; 133 | } 134 | 135 | Game_Battler.prototype.resetReserve = function() { 136 | this._hpReserved = 0; 137 | this._mpReserved = 0; 138 | this._tpReserved = 0; 139 | } 140 | 141 | Game_Battler.prototype.updateReserve = function() { 142 | this.resetReserve(); 143 | for(let i = 0; i < this._stskills.length; i++) { 144 | if(this._stskills[i] && $dataSkills[i] && $dataSkills[i].meta && 145 | $dataSkills[i].meta.type == 'toggle') { 146 | 147 | let skillInfo = $dataSkills[i]; 148 | let hp = this.skillHpCost($dataSkills[i]); 149 | let mp = this.skillMpCost($dataSkills[i]); 150 | let tp = this.skillTpCost($dataSkills[i]); 151 | 152 | if(this._stskills[i].toggleState) { 153 | // We alread paid once, so we don't have to pay again. 154 | // this._hp -= hp; 155 | // this._mp -= mp; 156 | // this._tp -= tp; 157 | this._hpReserved += hp; 158 | this._mpReserved += mp; 159 | this._tpReserved += tp; 160 | } 161 | else { 162 | // We already paid for the skills in the default action, so we double 163 | // the payback here. 164 | this._hp += hp * 2; 165 | this._mp += mp * 2; 166 | this._tp += tp * 2; 167 | } 168 | 169 | } 170 | } 171 | } 172 | 173 | // Game_Battler.prototype.refresh = function() { 174 | // Kru.STog.Game_Battler___refresh.call(this); 175 | // this.updateReserve(); 176 | // } 177 | 178 | // Confirm action is handled by the Scene. 179 | Kru.STog.Scene_Skill___useItem = Scene_Skill.prototype.useItem; 180 | Scene_Skill.prototype.useItem = function() { 181 | Kru.STog.Scene_Skill___useItem.call(this); 182 | 183 | let item = this.item(); 184 | this._actor._stskills[item.id].toggleState = !this._actor._stskills[item.id].toggleState; 185 | 186 | for(let i = 0; i < item.effects.length; i++) { 187 | // Toggle state effects. 188 | if(item.effects[i].code === Game_Action.EFFECT_ADD_STATE) { 189 | if(this._actor._stskills[item.id].toggleState) { 190 | this._actor.addState(item.effects[i].dataId); 191 | } 192 | else { 193 | this._actor.removeState(item.effects[i].dataId); 194 | } 195 | } 196 | } 197 | this._actor.clearResult(); 198 | this._actor.updateReserve(); 199 | this._statusWindow.refresh(); 200 | 201 | } 202 | 203 | // First, we need a *little* more room to draw. 204 | Window_Base.prototype._sWindow = { 205 | leftCol: {width: 120} 206 | } 207 | 208 | Kru.STog.Window_Base___drawActorSimpleStatus = Window_Base.prototype.drawActorSimpleStatus; 209 | Window_Base.prototype.drawActorSimpleStatus = function(actor, x, y, width) { 210 | let width1 = this._sWindow.leftCol.width; 211 | let lineHeight = this.lineHeight(); 212 | let x2 = x + width1; 213 | let width2 = width - width1 - this.textPadding(); 214 | this.drawActorName(actor, x, y); 215 | this.drawActorLevel(actor, x, y + lineHeight * 1); 216 | this.drawActorIcons(actor, x, y + lineHeight * 2); 217 | this.drawActorClass(actor, x2, y, width2); 218 | this.drawActorHp(actor, x2, y + lineHeight * 1, width2); 219 | this.drawActorMp(actor, x2, y + lineHeight * 2, width2); 220 | }; 221 | 222 | // Move the class all the way to the right. 223 | Kru.STog.Window_Base___drawActorClass = Window_Base.prototype.drawActorClass; 224 | Window_Base.prototype.drawActorClass = function(actor, x, y, width) { 225 | width = width || 168; 226 | this.resetTextColor(); 227 | this.drawText(actor.currentClass().name, x, y, width, 'right'); 228 | }; 229 | 230 | // Squeeze our level over to the left. 231 | Kru.STog.Window_Base___drawActorLevel = Window_Base.prototype.drawActorLevel; 232 | Window_Base.prototype.drawActorLevel = function(actor, x, y) { 233 | let width1 = this._sWindow.leftCol.width; 234 | this.changeTextColor(this.systemColor()); 235 | this.drawText(TextManager.levelA, x, y, 48); 236 | this.resetTextColor(); 237 | this.drawText(actor.level, x + Math.ceil(width1 / 2), y, 36, 'right'); 238 | }; 239 | 240 | // Show our reserved values. 241 | Kru.STog.Window_Base___drawActorHp = Window_Base.prototype.drawActorHp; 242 | Window_Base.prototype.drawActorHp = function(actor, x, y, width) { 243 | width = width || 186; 244 | let color1 = this.hpGaugeColor1(); 245 | let color2 = this.hpGaugeColor2(); 246 | let gaugeW = width; 247 | let textW = width; 248 | let gaugeR = 0; 249 | let textR = 70; 250 | let mhp = actor.mhp; 251 | 252 | if(actor._hpReserved) { 253 | textW = textW - textR; 254 | 255 | let percent = actor._hpReserved / actor.mhp; 256 | gaugeR = Math.floor(percent * gaugeW); 257 | gaugeW = gaugeW - gaugeR; 258 | this.drawGauge(x+gaugeW+5, y, gaugeR-5, actor.hpRate(), this.textColor(22), this.textColor(23)); 259 | mhp -= actor._hpReserved; 260 | } 261 | this.drawGauge(x, y, gaugeW, actor.hpRate(), color1, color2); 262 | this.changeTextColor(this.systemColor()); 263 | this.drawText(TextManager.hpA, x, y, 44); 264 | this.drawCurrentAndMax(actor.hp, mhp, x, y, textW, 265 | this.hpColor(actor), this.normalColor()); 266 | this.changeTextColor(this.textColor(23)); 267 | if(actor._hpReserved) { 268 | this.drawText('('+actor._hpReserved+')', x+textW+5, y, textR, 'right'); 269 | } 270 | this.resetTextColor(); 271 | }; 272 | 273 | Kru.STog.Window_Base___drawActorMp = Window_Base.prototype.drawActorMp; 274 | Window_Base.prototype.drawActorMp = function(actor, x, y, width) { 275 | width = width || 186; 276 | var color1 = this.mpGaugeColor1(); 277 | var color2 = this.mpGaugeColor2(); 278 | let gaugeW = width; 279 | let textW = width; 280 | let gaugeR = 0; 281 | let textR = 70; 282 | let mmp = actor.mmp; 283 | 284 | if(actor.mmp && actor._mpReserved) { 285 | textW = textW - textR; 286 | 287 | let percent = actor._mpReserved / actor.mmp; 288 | gaugeR = Math.floor(percent * gaugeW); 289 | gaugeW = gaugeW - gaugeR; 290 | this.drawGauge(x+gaugeW+5, y, gaugeR-5, actor.hpRate(), this.textColor(22), this.textColor(23)); 291 | 292 | mmp -= actor._mpReserved; 293 | } 294 | this.drawGauge(x, y, gaugeW, actor.mpRate(), color1, color2); 295 | this.changeTextColor(this.systemColor()); 296 | this.drawText(TextManager.mpA, x, y, 44); 297 | this.drawCurrentAndMax(actor.mp, mmp, x, y, textW, 298 | this.mpColor(actor), this.normalColor()); 299 | this.changeTextColor(this.textColor(23)); 300 | if(actor._mpReserved) { 301 | this.drawText('('+actor._mpReserved+')', x+textW+5, y, textR, 'right'); 302 | } 303 | this.resetTextColor(); 304 | }; 305 | 306 | Kru.STog.Game_BattlerBase___hpRate = Game_BattlerBase.prototype.hpRate; 307 | Game_BattlerBase.prototype.hpRate = function() { 308 | let reserve = this._hpReserved || 0; 309 | return (this.hp - reserve) / (this.mhp - reserve); 310 | }; 311 | 312 | Kru.STog.Game_BattlerBase___mpRate = Game_BattlerBase.prototype.mpRate; 313 | Game_BattlerBase.prototype.mpRate = function() { 314 | let reserve = this._mpReserved || 0; 315 | return this.mmp > 0 ? (this.mp - reserve) / (this.mmp - reserve) : 0; 316 | }; 317 | 318 | /* TODO 319 | Game_BattlerBase.prototype.paySkillCost = function(skill) { 320 | this._mp -= this.skillMpCost(skill); 321 | this._tp -= this.skillTpCost(skill); 322 | }; 323 | */ 324 | -------------------------------------------------------------------------------- /Kru_SkillTree.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Skill Tree 3 | // Version: 1.0.1 4 | //============================================================================= 5 | /*: 6 | * @plugindesc Skill Tree system 7 | * 8 | * @author Krusynth 9 | * 10 | * @help 11 | * ============================================================================ 12 | * Information 13 | * ============================================================================ 14 | * 15 | * Adds the ability for players to buy skills from a skill tree. Skills can have 16 | * levels which can impact their efficacy and cost. 17 | * 18 | * @param Skill Points 19 | * @desc Number of skill points to award per level 20 | * @default 1 21 | * 22 | * @param Initial Points 23 | * @desc Number of skill points characters start with 24 | * @default 0 25 | * 26 | * @param Set Text 27 | * @desc Text for the Set command in the Skill menu. 28 | * @default Set 29 | * 30 | * Terms & Conditions 31 | * This plugin is free for non-commercial and commercial use. 32 | */ 33 | 34 | /* 35 | * TODO: 36 | * Add support for items that add bonuses to skills. 37 | * Fix sounds on class change. 38 | * Document skill parameters. 39 | * Allow custom cost for skills (items, strength, etc). 40 | * Add additional requirements to unlock skills (strength, etc). 41 | * Change sound to buzzer if you can't buy more levels. 42 | * If a class has a skill by default, set the level to some value. 43 | * Restructure the entire skill window, to put the Help info on bottom. 44 | */ 45 | 46 | var Imported = Imported || {}; 47 | Imported.Kru_SkillTree = "1.0.0"; 48 | 49 | var Kru = Kru || {}; 50 | Kru.ST = { 51 | config: {} 52 | }; 53 | 54 | Kru.ST.Parameters = PluginManager.parameters('Kru_SkillTree'); 55 | Kru.ST.Parameters['Skill Points'] = Number(Kru.ST.Parameters['Skill Points']); 56 | Kru.ST.Parameters['Initial Points'] = Number(Kru.ST.Parameters['Initial Points']); 57 | 58 | if(!Imported.Kru_Core) { 59 | alert("Kru_SkillTree requires Kru_Core."); 60 | throw new Error("Kru_SkillTree requires Kru_Core."); 61 | } 62 | 63 | if(!Imported.Kru_SkillCore) { 64 | alert("Kru_SkillTree requires Kru_SkillCore."); 65 | throw new Error("Kru_SkillTree requires Kru_SkillCore."); 66 | } 67 | 68 | // Helper methods 69 | 70 | // Test if the given actor has a skill, return the level if so. 71 | function actorSkill(actorId, skill) { 72 | // If our skill is a name not an id. 73 | if(!Number.isInteger(skill)) { 74 | for(let i = 0; i < $dataSkills.length; i++) { 75 | if($dataSkills[i] && $dataSkills[i].name && 76 | $dataSkills[i].name.toLowerCase() == skill.toLowerCase() 77 | ) { 78 | skill = $dataSkills[i].id; 79 | break; 80 | } 81 | } 82 | } 83 | if($gameActors._data[actorId]._stskills[skill]) { 84 | return $gameActors._data[actorId]._stskills[skill].level; 85 | } 86 | 87 | return 0; 88 | } 89 | 90 | // Test if anyone in the party has a skill at a particular level (defaults to 1). 91 | function partySkill(skill, level) { 92 | level = level || 1; 93 | let result = $gameParty._actors.filter(function(actorId) { 94 | let skillLevel = actorSkill(actorId, skill); 95 | return skillLevel && skillLevel >= level; 96 | }); 97 | if(!result.length) { 98 | result = false; 99 | } 100 | return result; 101 | } 102 | 103 | // Setup 104 | Kru.ST.Game_Actor_Setup = Game_Actor.prototype.setup; 105 | Game_Actor.prototype.setup = function (actorId) { 106 | Kru.ST.Game_Actor_Setup.call(this, actorId); 107 | if(typeof this._skillPoints == 'undefined') { 108 | this._skillPoints = Number(Kru.ST.Parameters['Initial Points']); 109 | } 110 | // We store our saved skills under actor._stskills 111 | if(typeof this._stskills == 'undefined') { 112 | this._stskills = []; 113 | } 114 | }; 115 | 116 | // Level up 117 | Kru.ST.Game_Actor_levelUp = Game_Actor.prototype.levelUp; 118 | Game_Actor.prototype.levelUp = function () { 119 | Kru.ST.Game_Actor_levelUp.call(this); 120 | this._skillPoints += Number(Kru.ST.Parameters['Skill Points']); 121 | }; 122 | 123 | 124 | /* Add option to skill window */ 125 | Kru.ST.Window_SkillType_makeCommandList = 126 | Window_SkillType.prototype.makeCommandList; 127 | 128 | Window_SkillType.prototype.makeCommandList = function() { 129 | this.addCustomCommandBefore(); 130 | Kru.ST.Window_SkillType_makeCommandList.call(this); 131 | this.addCustomCommandAfter(); 132 | }; 133 | 134 | if (!Window_SkillType.prototype.addCustomCommandBefore) { 135 | Window_SkillType.prototype.addCustomCommandBefore = function() { 136 | }; 137 | }; 138 | 139 | if (!Window_SkillType.prototype.addCustomCommandAfter) { 140 | Window_SkillType.prototype.addCustomCommandAfter = function() { 141 | }; 142 | }; 143 | 144 | Kru.ST.Window_SkillType_addCustomCommandAfter = 145 | Window_SkillType.prototype.addCustomCommandAfter; 146 | 147 | Window_SkillType.prototype.addCustomCommandAfter = function() { 148 | Kru.ST.Window_SkillType_addCustomCommandAfter.call(this); 149 | if (this.findExt('skillTree') === -1) { 150 | this.addSkillsCommand(); 151 | } 152 | }; 153 | 154 | Window_SkillType.prototype.windowWidth = function() { 155 | return 320; 156 | }; 157 | 158 | Window_SkillType.prototype.maxCols = function() { 159 | return 2; 160 | }; 161 | 162 | Window_SkillType.prototype.addSkillsCommand = function() { 163 | if(this._actor) { 164 | 165 | let cmdText = Kru.ST.Parameters['Set Text']; 166 | let cmdWidth = this.textWidth(cmdText)+ this.spacing(); 167 | 168 | for(let i = 0; i < this._list.length; i = i+2) { 169 | this._list[i].width = this.windowWidth() - (cmdWidth + this.padding * 2 + this.spacing()); 170 | 171 | this._list.splice(i + 1, 0, { 172 | enabled: true, 173 | ext: ['set', this._list[i].ext], 174 | name: cmdText, 175 | symbol: 'skill', 176 | width: cmdWidth 177 | }); 178 | } 179 | } 180 | }; 181 | 182 | Window_SkillType.prototype.itemRect = function(index) { 183 | let rect = new Rectangle(); 184 | let maxCols = this.maxCols(); 185 | let item = this._list[index]; 186 | rect.width = this.itemWidth(index); 187 | rect.height = this.itemHeight(index); 188 | rect.x = 0 - this._scrollX; 189 | 190 | let offset = index % maxCols; 191 | if(offset) { 192 | for(let i = 1; i <= offset; i++) { 193 | let prev = this._list[index - i]; 194 | if(prev) { 195 | rect.x += this.itemWidth(index - i) + this.spacing(); 196 | } 197 | } 198 | } 199 | 200 | rect.y = Math.floor(index / maxCols) * rect.height - this._scrollY; 201 | return rect; 202 | }; 203 | 204 | Kru.ST.Window_SkillType___itemWidth = Window_SkillType.prototype.itemWidth; 205 | Window_SkillType.prototype.itemWidth = function(index) { 206 | let item = this._list[index]; 207 | if(item) { 208 | if(item.width) { 209 | return item.width; 210 | } 211 | else { 212 | return Kru.ST.Window_SkillType___itemWidth.call(this); 213 | } 214 | } 215 | } 216 | 217 | /* Skill Tree Window */ 218 | function Kru_TreeWindow() { 219 | this.initialize.apply(this, arguments); 220 | }; 221 | 222 | Kru_TreeWindow.prototype = Object.create(Kru_CustomListWindow.prototype); 223 | 224 | Kru_TreeWindow.prototype.initialize = function(win) { 225 | Kru_CustomListWindow.prototype.initialize.call(this, win); 226 | 227 | let category = win.category; 228 | 229 | let classSkills = this.getClassSkills(this.actor._classId); 230 | let skills = classSkills[win.category]; 231 | 232 | this.lines = []; 233 | this._data = []; 234 | 235 | if(typeof(skills) != 'undefined') { 236 | for(let i = 0; i < skills.length; i++) { 237 | let skill = skills[i]; 238 | if(skill.id === 'LINE') { 239 | this.lines.push(skill); 240 | } 241 | else { 242 | skill = Object.assign(skill, $dataSkills[skill.id]); 243 | skill._name = skills[i].name; 244 | skill._description = skills[i].description; 245 | skill = this.updateSkill(skills[i]); 246 | this._data.push(skill); 247 | } 248 | } 249 | } 250 | 251 | if(this._data && this._data.length) { 252 | this._index = 0; 253 | } 254 | 255 | this.refresh(); 256 | 257 | this.select(0); 258 | }; 259 | 260 | Kru_TreeWindow.prototype.getClassSkills = function(classId) { 261 | let classData = $dataClasses[classId]; 262 | let skills = {}; 263 | 264 | if(classData.meta) { 265 | if(classData.meta.parents) { 266 | // Add the skills from our parents. 267 | for(let i = 0; i < classData.meta.parents.length; i++) { 268 | skills = this.mergeSkillTypes( 269 | skills, 270 | this.getClassSkills(parseInt(classData.meta.parents[i])) 271 | ); 272 | } 273 | } 274 | 275 | if(classData.meta.skills) { 276 | skills = this.mergeSkillTypes( 277 | skills, 278 | classData.meta.skills 279 | ); 280 | } 281 | } 282 | 283 | return skills; 284 | } 285 | 286 | Kru_TreeWindow.prototype.mergeSkillTypes = function(skills, otherSkills) { 287 | let types = Object.keys(otherSkills); 288 | for(let j = 0; j < types.length; j++) { 289 | let type = types[j]; 290 | if(typeof skills[type] === 'undefined') { 291 | skills[type] = []; 292 | } 293 | skills[type] = skills[type].concat(otherSkills[type]); 294 | } 295 | return skills; 296 | } 297 | 298 | Kru_TreeWindow.prototype.updateSkill = function(skill) { 299 | // Show the description as the name and description combined. 300 | skill.description = skill._name + ' - ' + skill._description; 301 | 302 | // Show any requirements in the description. 303 | if(skill.meta.req) { 304 | // Level requirement. 305 | if(skill.meta.req.level) { 306 | skill.description += ' Must be level ' + 307 | String(skill.meta.req.level) + '.'; 308 | } 309 | 310 | // Previous skill requirement. 311 | if(skill.meta.req.skill) { 312 | let reqs = []; 313 | for(let j = 0; j < skill.meta.req.skill.length; j++) { 314 | let req = $dataSkills[skill.meta.req.skill[j].id].name; 315 | if(skill.meta.req.skill[j].level) { 316 | req += ' level ' + String(skill.meta.req.skill[j].level); 317 | } 318 | reqs.push(req); 319 | } 320 | skill.description += ' Requires ' + reqs.join(' and ') + '.'; 321 | } 322 | } 323 | 324 | // Show the current/max level as the name. 325 | let lvl = 0; 326 | if(this.actor._stskills[skill.id]) { 327 | lvl = Number(this.actor._stskills[skill.id].level); 328 | } 329 | let max = skill.meta.max || 1; 330 | 331 | skill.name = String(lvl) + '/' + String(max); 332 | 333 | if(!this.skillAvailable(this.actor, skill)) { 334 | skill.disabled = true; 335 | } 336 | else { 337 | skill.disabled = false; 338 | } 339 | 340 | return skill; 341 | }; 342 | 343 | Kru_TreeWindow.prototype.updateAllSkills = function() { 344 | for(let i = 0; i < this._data.length; i++) { 345 | this._data[i] = this.updateSkill(this._data[i]); 346 | } 347 | } 348 | 349 | Kru_TreeWindow.prototype.onOk = function() { 350 | let skill = this._data[this.index()]; 351 | 352 | // Failure states. 353 | if(this.actor._skillPoints == 0) { 354 | return this.failState(); 355 | } 356 | 357 | // Requirements. 358 | if(!this.skillAvailable(this.actor, skill)) { 359 | return this.failState(); 360 | } 361 | 362 | // Past the max. 363 | if(skill.meta.max && this.actor._stskills[skill.id] && 364 | this.actor._stskills[skill.id].level == skill.meta.max) { 365 | return this.failState(); 366 | } 367 | 368 | // Increment the skill for the actor. 369 | if(!this.actor._stskills[skill.id]) { 370 | this.actor._stskills[skill.id] = { 371 | level: 0 372 | }; 373 | } 374 | this.actor._stskills[skill.id].level++; 375 | this.actor._skillPoints--; 376 | 377 | this.actor.learnSkill(skill.id); 378 | 379 | this.updateAllSkills(); 380 | this.refresh(); 381 | this.activate(); 382 | }; 383 | 384 | Kru_TreeWindow.prototype.skillAvailable = function(actor, skill) { 385 | if(skill.meta.req) { 386 | if(skill.meta.req.level && actor._level < skill.meta.req.level) { 387 | return false 388 | } 389 | if(skill.meta.req.skill) { 390 | for(sA_i = 0; sA_i < skill.meta.req.skill.length; sA_i++) { 391 | let req = skill.meta.req.skill[sA_i]; 392 | if(!actor._stskills[req.id]) { 393 | return false; 394 | } 395 | 396 | if(req.level && actor._stskills[req.id].level < req.level) { 397 | return false; 398 | } 399 | } 400 | } 401 | } 402 | 403 | return true; 404 | }; 405 | 406 | Kru_TreeWindow.prototype.redrawItem = function(index) { 407 | // TODO: Make this more efficient. At the moment, we don't know where lines 408 | // have been drawn, so we can't just clear a rectangle. 409 | this.updateSkill(this._data[index]); 410 | this.refresh(); 411 | this.select(index); 412 | }; 413 | 414 | Kru_TreeWindow.prototype.drawHeader = function() { 415 | // let content = $dataClasses[this.actor._classId].name; 416 | let content = $dataSystem.skillTypes[this._win.category]; 417 | 418 | // Arbitrarily set this in the top left corner. 419 | this.contents.drawText(content, 0, 10, 250, 10, 'left'); 420 | }; 421 | 422 | Kru_TreeWindow.prototype.drawFooter = function() { 423 | let content = String(this.actor._skillPoints) + ' Pts'; 424 | // Arbitrarily set this in the bottom right corner. 425 | this.contents.drawText(content, 670, 415, 100, 10, 'right'); 426 | }; 427 | 428 | // Add new window type to the Window Manager 429 | Kru.helpers.windowHandlers['skilltree'] = Kru_TreeWindow; 430 | 431 | 432 | /* Override select of Set Skills */ 433 | Kru.ST.Scene_Skill__commandSkill = Scene_Skill.prototype.commandSkill; 434 | 435 | Scene_Skill.prototype.commandSkill = function() { 436 | if(Array.isArray(this._skillTypeWindow._skillWindow._stypeId) && 437 | this._skillTypeWindow._skillWindow._stypeId[0] === 'set') { 438 | SceneManager.push(Scene_SkillChoice); 439 | SceneManager.prepareNextScene(this._skillTypeWindow._skillWindow._stypeId[1]); 440 | } 441 | else { 442 | Kru.ST.Scene_Skill__commandSkill.call(this); 443 | } 444 | }; 445 | 446 | function Scene_SkillChoice() { 447 | this.initialize.apply(this, arguments); 448 | }; 449 | 450 | Scene_SkillChoice.prototype = Object.create(Scene_ItemBase.prototype); 451 | Scene_SkillChoice.prototype.constructor = Scene_Skill; 452 | 453 | Scene_SkillChoice.prototype.initialize = function() { 454 | Scene_ItemBase.prototype.initialize.call(this, arguments); 455 | }; 456 | 457 | Scene_SkillChoice.prototype.prepare = function(category) { 458 | this._category = category; 459 | } 460 | 461 | Scene_SkillChoice.prototype.create = function() { 462 | Scene_ItemBase.prototype.create.call(this); 463 | 464 | this.wm = new Kru.helpers.WindowManager(this); 465 | 466 | // Top Window: skill tree. 467 | let treeWin = this.wm.addWindow({ 468 | width: 1, 469 | height: 0.75, 470 | type: 'skilltree', 471 | category: this._category 472 | }); 473 | 474 | treeWin.window.activate(); 475 | 476 | // Bottom Window: skill details. 477 | let infoWindow = this.wm.addWindow({ 478 | width: 1, 479 | height: .25, 480 | type: 'help', 481 | content: '', 482 | setItem: function(item) { 483 | this.contents.clear(); 484 | 485 | let content = ''; 486 | if(item) { 487 | content = item.description; 488 | } 489 | this.setText(content); 490 | } 491 | }); 492 | 493 | treeWin.window.setHelpWindow(infoWindow.window); 494 | }; 495 | -------------------------------------------------------------------------------- /Kru_UserSwap.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Kru_UserSwap.js 3 | //============================================================================= 4 | 5 | /*: 6 | * @plugindesc Swaps parties on map change. 7 | * @author Krusynth 8 | * 9 | * @help This plugin extends Hime's Party Manager to automatically swap parties 10 | * on map load. Simply add a Note to the map such as and that party 11 | * will automatically be selected on map load. 12 | * 13 | * This also adds an event handler when the Party is changed. This allows you 14 | * to set values on each swap. For instance, you can create an event and run a 15 | * custom script like the following to turn Stepping on and off when that party 16 | * loads. 17 | * 18 | * Party.on(1, 'switch', '$gamePlayer._stepAnime = false;'); 19 | * Party.on(2, 'switch', '$gamePlayer._stepAnime = true;'); 20 | */ 21 | 22 | var Kru = Kru || {}; 23 | Kru.US = { 24 | }; 25 | 26 | // Automatically switch parties on transfer if the map has a party tag. 27 | Kru.US.Game_Player__performTransfer = Game_Player.prototype.performTransfer; 28 | Game_Player.prototype.performTransfer = function() { 29 | if( 30 | $dataMap.meta && 31 | typeof $dataMap.meta.party !== 'undefined' && 32 | $gameParties._activeId !== $dataMap.meta.party 33 | ) { 34 | if (this.isTransferring()) { 35 | let mapId = $gameMap.mapId(); 36 | if(this._newMapId !== $gameMap.mapId()) { 37 | mapId = this._newMapId; 38 | } 39 | 40 | $gameParties._parties[$dataMap.meta.party].setLocation(mapId, this._newX, this._newY); 41 | Party.switch($dataMap.meta.party); 42 | 43 | } 44 | } 45 | Kru.US.Game_Player__performTransfer.call(this); 46 | } 47 | 48 | // Add event handler to Party. 49 | Party.on = function(id, event, fn) { 50 | return $gameParties._parties[id].on(event, fn); 51 | } 52 | 53 | Kru.US.Game_Party__initialize = Game_Party.prototype.initialize; 54 | Game_Party.prototype.initialize = function() { 55 | Kru.US.Game_Party__initialize.call(this); 56 | this.__events = {}; 57 | } 58 | 59 | Game_Party.prototype.on = function(event, fn) { 60 | if(typeof this.__events[event] === 'undefined') { 61 | this.__events[event] = []; 62 | } 63 | 64 | this.__events[event].push(fn); 65 | } 66 | 67 | Game_Party.prototype.onSwitch = function(fn) { 68 | this.on('switch', fn); 69 | } 70 | 71 | Game_Party.prototype.trigger = function(event) { 72 | if(this.__events[event] && this.__events[event].length) { 73 | this.__events[event].forEach(fn => { 74 | eval(fn); 75 | }); 76 | } 77 | } 78 | 79 | Kru.US.Game_Parties__switchParty = Game_Parties.prototype.switchParty; 80 | Game_Parties.prototype.switchParty = function(id) { 81 | let party = Kru.US.Game_Parties__switchParty.call(this, id); 82 | party.trigger('switch'); 83 | return party; 84 | }; -------------------------------------------------------------------------------- /Kru_VariableText.js: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Variable Text 3 | // Version: 1.0.2 4 | //============================================================================= 5 | /*: 6 | * @plugindesc v1.0.2 Replace text using a datafile. 7 | * 8 | * @author Krusynth 9 | * 10 | * @help 11 | * ============================================================================ 12 | * Information 13 | * ============================================================================ 14 | * 15 | * Loads a JSON file containing a dictionary of text to replace in messages. Use 16 | * \vt[my variable] or $my variable$ placeholders to replace with your specified 17 | * text. By default, the datafile will be /data/VariableText.json but this can 18 | * be customized below. 19 | * 20 | * Works with Yanfly Message Core. 21 | * 22 | * Example datafile: 23 | * 24 | * {"mayor": "Mayor Gigglesworth", "cat": "Catish Kittington"} 25 | * 26 | * @param Datafile 27 | * @desc The name of the data file to load. ".json" will be added to this automatically. 28 | * @default VariableText 29 | * @type file 30 | * 31 | * Terms & Conditions 32 | * This plugin is free for non-commercial and commercial use. 33 | */ 34 | 35 | var Imported = Imported || {}; 36 | Imported.Kru_VariableText = "1.0.0"; 37 | 38 | var Kru = Kru || {}; 39 | Kru.VT = {}; 40 | Kru.VT.Parameters = PluginManager.parameters('Kru_VariableText'); 41 | 42 | Kru.VT.init = function() { 43 | DataManager.loadDataFile('kruVariableText', Kru.VT.Parameters.Datafile+'.json'); 44 | } 45 | Kru.VT.init(); 46 | 47 | Kru.VT.Window_Base_convertExtraEscapeCharacters = 48 | Window_Base.prototype.convertExtraEscapeCharacters; 49 | 50 | Window_Base.prototype.convertExtraEscapeCharacters = function(text) { 51 | text = Kru.VT.convertVariableText(text); 52 | text = Kru.VT.Window_Base_convertExtraEscapeCharacters.call(this, text); 53 | return text; 54 | }; 55 | 56 | Kru.VT.replaceVariableText = function(match, name) { 57 | if(typeof kruVariableText[name] !== 'undefined') { 58 | return kruVariableText[name]; 59 | } 60 | else return ''; 61 | }; 62 | 63 | Kru.VT.convertVariableText = function(text) { 64 | text = text.replace(/\x1bvt\[([^\]]+)\]/gi, Kru.VT.replaceVariableText); 65 | text = text.replace(/\$([^\$]+)\$/gi, Kru.VT.replaceVariableText); 66 | return text; 67 | }; 68 | 69 | -------------------------------------------------------------------------------- /Kru_VehicleInsides.js: -------------------------------------------------------------------------------- 1 | /*: 2 | * Vehicle Insides 3 | * 4 | * @plugindesc 1.0 Automatically creates vehicle insides, 5 | * 6 | * @author Krusynth 7 | * 8 | * @help 9 | * This plugin allows you to easily create maps for the insides of vehicles, 10 | * like the Big Whale in Final Fantasy IV or the airships in Final Fantasy VI. 11 | * 12 | * You don't need to setup any fancy transfers to get started, your map only 13 | * needs to be named the same as the vehicle you're using it for (.e.g airship). 14 | * 15 | * To take off, create an event that the player can interact with (such as a 16 | * steering wheel or controls) to trigger this custom script: 17 | * Kru.VI.launchVehicle(); 18 | * 19 | * You can also create an exit from the vehicle back to the main map with the 20 | * custom script: 21 | * Kru.VI.leaveVehicle(); 22 | * 23 | * To customize where the player starts on the new map, you can add a Note to 24 | * the map, with the x & y coordinates of the player, and (optionally) the 25 | * direction they will be facing : 26 | * 27 | * 28 | * Terms & Conditions 29 | * This plugin is MIT Licensed. (Free for non-commercial and commercial use.) 30 | */ 31 | 32 | var Imported = Imported || {}; 33 | Imported.Kru_VehicleInsides = 1.0; 34 | 35 | var Kru = Kru || {}; 36 | Kru.VI = { 37 | 'loaded': false, 38 | 'vehicles': { 39 | 'boat': {}, 40 | 'ship': {}, 41 | 'airship': {} 42 | }, 43 | 'previousLocation': null 44 | }; 45 | 46 | /*** Helpers ***/ 47 | if(!Kru.helpers) { 48 | Kru.helpers = {} 49 | } 50 | 51 | Kru.helpers.getMapData = function(mapId) { 52 | var filename = 'Map%1.json'.format(mapId.padZero(3)); 53 | return this.getFileData(filename); 54 | }; 55 | 56 | // Gets data from a JSON file. 57 | // Unlike the original version, this is synchronous and returns the result. 58 | Kru.helpers.getFileData = function(src) { 59 | var data; 60 | 61 | var xhr = new XMLHttpRequest(); 62 | var url = 'data/' + src; 63 | xhr.open('GET', url, false); 64 | xhr.overrideMimeType('application/json'); 65 | xhr.onload = function() { 66 | if (xhr.status < 400) { 67 | data = JSON.parse(xhr.responseText); 68 | DataManager.extractMetadata(data); 69 | } 70 | }; 71 | xhr.onerror = function() { 72 | DataManager._errorUrl = DataManager._errorUrl || url; 73 | }; 74 | xhr.send(); 75 | 76 | return data; 77 | } 78 | 79 | DataManager.Kru__isDatabaseLoadedOriginal = DataManager.isDatabaseLoaded; 80 | DataManager.isDatabaseLoaded = function() { 81 | if (!DataManager.Kru__isDatabaseLoadedOriginal()) { 82 | return false; 83 | } 84 | else if(!Kru.VI.loaded) { 85 | // Loop through all maps and match to vehicle names. 86 | for(var i = 0; i < $dataMapInfos.length; i++) { 87 | var map = $dataMapInfos[i]; 88 | if(map instanceof Object && map.name) { 89 | var name = map.name.toLowerCase(); 90 | 91 | if(Object.keys(Kru.VI.vehicles).indexOf(name) > -1) { 92 | Kru.VI.vehicles[name].map = $dataMapInfos[i]; 93 | var mapData = Kru.helpers.getMapData($dataMapInfos[i].id); 94 | Kru.VI.vehicles[name].map.meta = mapData.meta; 95 | } 96 | } 97 | } 98 | Kru.VI.loaded = true; 99 | } 100 | return true; 101 | }; 102 | 103 | 104 | // Replace waitCount() with a function that calls a callback. 105 | Game_Interpreter.prototype.registerWaitCallback = function(event, callback) { 106 | this.__waitCallback = this.__waitCallback || {}; 107 | this.__waitCallback[event] = this.__waitCallback[event] || []; 108 | this.__waitCallback[event].push(callback); 109 | }; 110 | 111 | Game_Interpreter.prototype.waitCallback = function(event) { 112 | this.__waitCallback = this.__waitCallback || {}; 113 | this.__waitCallback[event] = this.__waitCallback[event] || []; 114 | 115 | while(this.__waitCallback[event].length) { 116 | this.__waitCallback[event].shift()(); 117 | } 118 | }; 119 | 120 | Game_Interpreter.prototype.Kru__updateWaitCountOriginal = Game_Interpreter.prototype.updateWaitCount; 121 | 122 | Game_Interpreter.prototype.updateWaitCount = function() { 123 | var prevVal = this._waitCount; 124 | var returnVal = this.Kru__updateWaitCountOriginal(); 125 | 126 | if(prevVal > 0 && this._waitCount === 0) { 127 | this.waitCallback(this._waitMode); 128 | } 129 | 130 | return returnVal; 131 | }; 132 | 133 | // Transfer helper that allows a callback after the transfer. 134 | Kru.helpers.transfer = function(mapId, x, y, direction, transition, callback) { 135 | if(callback) { 136 | $gameMap._interpreter.registerWaitCallback('transfer', callback); 137 | } 138 | 139 | $gameMap._interpreter.setWaitMode('transfer'); 140 | $gamePlayer.reserveTransfer( 141 | parseInt(mapId), 142 | parseInt(x), 143 | parseInt(y), 144 | parseInt(direction), 145 | parseInt(transition) 146 | ); 147 | } 148 | 149 | /*** End Helpers ***/ 150 | 151 | 152 | /* Vehicle */ 153 | 154 | // Game_Vehicle.prototype.Kru__getOnOriginal = Game_Vehicle.prototype.getOn; 155 | 156 | // Game_Vehicle.prototype.getOn = function() { 157 | // $gameSystem.saveWalkingBgm(); 158 | // this.playBgm(); 159 | // }; 160 | 161 | 162 | Game_Player.prototype.Kru__getOnVehicleOriginal = Game_Player.prototype.getOnVehicle; 163 | 164 | Game_Player.prototype.getOnVehicle = function() { 165 | if (!this.areFollowersGathering() && !this.isMoving()) { 166 | var direction = this.direction(); 167 | var x1 = this.x; 168 | var y1 = this.y; 169 | var x2 = $gameMap.roundXWithDirection(x1, direction); 170 | var y2 = $gameMap.roundYWithDirection(y1, direction); 171 | 172 | var vehicleType; 173 | var vehicleId = -1; 174 | 175 | if ($gameMap.airship().pos(x1, y1)) { 176 | vehicleType = 'airship'; 177 | vehicleId = 2; 178 | } else if ($gameMap.ship().pos(x2, y2)) { 179 | vehicleType = 'ship'; 180 | vehicleId = 1; 181 | } else if ($gameMap.boat().pos(x2, y2)) { 182 | vehicleType = 'boat'; 183 | vehicleId = 0; 184 | } 185 | 186 | // Check for map 187 | if(vehicleType && Kru.VI.vehicles[vehicleType].map) { 188 | Kru.VI.previousLocation = { 189 | 'id': $gameMap._mapId, 190 | 'x': this._x, 191 | 'y': this._y, 192 | 'd': this._direction, 193 | 'vehicle': [vehicleType, vehicleId] 194 | }; 195 | 196 | var map = Kru.VI.vehicles[vehicleType].map; 197 | 198 | var start = []; 199 | if(map.meta.start) { 200 | start = map.meta.start.split(','); 201 | } 202 | 203 | var startx = start[0] || 0; 204 | var starty = start[1] || 0; 205 | var direction = start[2] || 0; 206 | var transition = start[3] || 0; 207 | 208 | Kru.helpers.transfer(map.id, startx, starty, direction, transition); 209 | 210 | return false; 211 | } 212 | else { 213 | return this.Kru__getOnVehicleOriginal(); 214 | } 215 | } 216 | } 217 | 218 | 219 | Kru.VI.leaveVehicle = function() { 220 | if(Kru.VI.previousLocation) { 221 | Kru.helpers.transfer( 222 | Kru.VI.previousLocation.id, 223 | Kru.VI.previousLocation.x, 224 | Kru.VI.previousLocation.y, 225 | Kru.VI.previousLocation.d, 226 | 0 227 | ); 228 | } 229 | } 230 | 231 | Kru.VI.launchVehicle = function() { 232 | if(Kru.VI.previousLocation) { 233 | $gameScreen.startFadeOut($gameMap._interpreter.fadeSpeed()); 234 | $gameMap._interpreter.wait($gameMap._interpreter.fadeSpeed()); 235 | 236 | var afterTransfer = function() { 237 | $gameScreen.startFadeIn($gameMap._interpreter.fadeSpeed()); 238 | $gameMap._interpreter.wait($gameMap._interpreter.fadeSpeed()); 239 | 240 | $gamePlayer.Kru__getOnVehicleOriginal(); 241 | }; 242 | 243 | Kru.helpers.transfer( 244 | Kru.VI.previousLocation.id, 245 | Kru.VI.previousLocation.x, 246 | Kru.VI.previousLocation.y, 247 | Kru.VI.previousLocation.d, 248 | 0, 249 | afterTransfer 250 | ); 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Bill Hunt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RPG Maker MV Plugins 2 | 3 | This is a collection of RPG Maker MV Plugins to add various features to your 4 | game. All of the plugins are free for commercial and non-commercial use, 5 | [licensed under the MIT License](./LICENSE). You do not need to give any sort of 6 | credit to use these plugins in your game. 7 | 8 | The following plugins are available in this repo: 9 | 10 | ## [Variable Text](Kru_VariableText.js) 11 | Replaces text in your game with a value defined in a JSON file. This allows you 12 | to set names of towns, people, etc. in one place and re-use the variable 13 | everywhere. 14 | 15 | ## [Clear Map Photos](Kru_ClearMapPhotos.js) 16 | Automatically clears all previously loaded photos whenever a map is loaded. This 17 | makes it easier to have parallax photos on your maps as they'll automatically be 18 | cleaned up. 19 | 20 | ## [Airship Events](Kru_AirshipEvents.js) 21 | By default, RPG Maker MV doesn't allow airships to interact with events. 22 | This plugin removes that limitation, allowing airships to land in towns, etc. 23 | 24 | ## [Vehicle Insides](Kru_VehicleInsides.js) 25 | This plugin allows authors to easily create maps for the insides of vehicles, like 26 | the Big Whale in Final Fantasy IV or the airships in Final Fantasy VI. The 27 | player will automatically be transported to the map upon entering the vehicle. 28 | 29 | ## [Multi-tile Events](Kru_MultitileEvents.js) 30 | This plugin allows for events that are bigger than one tiles, by expanding the 31 | collision box via notes. This works nicely for larger sprites (like giant 32 | monsters) that can still wander around like normal events. *Requires Kru Core.* 33 | 34 | ## [Map Merge](Kru_MapMerge.js) 35 | Allows authors to merge maps together, replacing a section of a map with a new 36 | map based on a given set of conditions. This is useful for dynamic events where 37 | a part of the map changes dramatically - e.g., a building is destroyed or lots 38 | of new characters appear. 39 | 40 | ## [Kru Core](Kru_Core.js) 41 | Core library for many of the other plugins so as to not repeatedly re-implement 42 | the same base functionality. The major features currently in this are 43 | streamlined window APIs, line drawing tools, and note tag parsers. 44 | 45 | ## [Party Window](Kru_PartyWindow.js) 46 | Shows more characters in the status window based on Max Battle Members setting 47 | in Yanfly's Party System. *Requires Yanfly Party System.* 48 | 49 | ## [Reputation](Kru_Reputation.js) 50 | A system for keeping track of the reputation of your party across multiple 51 | groups or factions. Allows you to have named values for different reputation 52 | values (e.g. "Known", "Famous", etc.). Works with builtin variables for ease of 53 | use. Also allows discounts at shops based on your reputation. You can even have 54 | special graphics for each group or faction. *Requires Kru Core.* [documentation](https://github.com/krusynth/rpgmakermv-plugins/wiki/Kru_Reputation) | [demo](https://games.billhunt.dev/demo/Kru_Reputation/) 55 | 56 | ## [Game Seed](Kru_GameSeed.js) 57 | Creates a custom "seed" number that can be used to create pseudo-random events 58 | that persist across the length of a game. E.g., one of several paths is blocked 59 | by debris, but the path changes each game. [documentation](https://github.com/krusynth/rpgmakermv-plugins/wiki/Kru_GameSeed) | [demo](https://games.billhunt.dev/demo/Kru_GameSeed/) 60 | 61 | ## [Skill Tree](Kru_SkillTree.js) 62 | *work in progress* 63 | 64 | Adds Skill Points (optionally awarded on level up) that can be used to purchase 65 | skills. Skills can also have multiple levels. *Requires Kru Core.* 66 | 67 | ## [Assign Stats](Kru_AssignStats.js) 68 | *work in progress* 69 | 70 | Adds Stat Points (optionally awarded on level up) that can be used to improve 71 | attributes (Attack, Defense, Luck, etc.). Traditional class-based level up stat 72 | points can also be disabled entirely. *Requires Kru Core.* 73 | 74 | ## [Class Change](Kru_ClassChange.js) 75 | *work in progress* 76 | 77 | Automatically triggers class change when certain conditions are met. Currently 78 | only checks on level up or when assinging stats with the Assign Stats plugin. 79 | *Requires Kru Core.* 80 | 81 | ## [Demo](Kru_Demo.js) 82 | This plugin makes it easier to deploy multiple games on a single webserver, by 83 | allowing each instance to share the core game assets. It also allows you to 84 | specify a custom html container element for the game to load in, so that you 85 | can create a wrapper frame around the game. [demo](https://games.billhunt.dev/demo/Kru_Reputation/) 86 | 87 | ## [Load Image Types](Kru_LoadImageTypes.js) 88 | This plugin allows for image types other than PNGs to be loaded for most uses. 89 | The default behavior for any files without an extension will remain the RPG 90 | Maker MV default to automatically add ".png" to the end before looking for the 91 | image. However, any files that include an extension will be loaded as-is. 92 | 93 | ## [Load Map Events](Kru_MapLoadEvents.js) 94 | Runs your own custom javascript when changing between maps. 95 | 96 | ## [Pipe Minigame](Kru_PipeMinigame.js) 97 | *work in progress* 98 | 99 | A small minigame where the player must connect a series of pipes. This plugin is 100 | currently under development, but works. There is no time limit or other 101 | restrictions currently. *Requires Kru Core.* 102 | 103 | To use this, you'll need to create an image for the tiles of the game. You can 104 | use [this image](https://raw.githubusercontent.com/wiki/krusynth/rpgmakermv-plugins/img/Kru_PipeMinigame/pipetiles.png) 105 | or use it as a template. 106 | 107 | ## [Previous Position](Kru_PreviousPosition.js) 108 | Remember a location and transfer the player back to that location. 109 | 110 | 111 | # Additions for other authors' plugins 112 | 113 | ## [Modern Algebra Extra Movement Frames](Kru_ExtraMovementFramesPatch.js) 114 | This plugin extends [Modern Algebra's Extra Movement Frames](http://rmrk.net/index.php?topic=50452.0) 115 | to fix an issue with the default filename pattern, which breaks on the web due 116 | to the use of the `%` character. Allows users to set their own regex patterns. 117 | 118 | ## [SumRndmDde FaceImages](Kru_SRD_FaceImages.js) 119 | This is a very tiny plugin that overrides the bust images of 120 | [SRD_AltMenuScreen_BustIcons.js](http://sumrndm.site/ams-busts-icons/) to use 121 | the built-in RPG Maker MV standard face images instead. 122 | 123 | ## [Hime User Swap](Kru_UserSwap.js) 124 | This plugin extends [Hime's Party Manager](http://himeworks.com/2016/02/party-manager-mv/) 125 | to automatically swap parties on map load. Simply add a Note to the map such as 126 | `` and that party will automatically be selected on map load. This also 127 | adds an event handler when the Party is changed. This allows you to set values 128 | on each swap. For instance, you can create an event and run a custom script to 129 | turn Stepping on and off when that party loads. 130 | 131 | ## [Battle Movement Frames](Kru_BattleMovementFrames.js) 132 | *work in progress* 133 | 134 | Adds movement frames to an enemy sprite in battle. This doesn't handle attacks 135 | or anything complicated - you're better off using 136 | [Yanfly's Animated Sideview Enemies](http://www.yanfly.moe/wiki/Animated_Sideview_Enemies_%28YEP%29) 137 | if you're looking for that sort of animation. *Requires Kru Core.* 138 | --------------------------------------------------------------------------------