异世界创造者吧 关注:94贴子:518

[修改]经验倍率和刷消耗品的mod

只看楼主收藏回复

//本篇修改搬运于steam社区讨论组,仅做交流用途,有需要者请前往原链接查看
(干,之前打了好多字直接被吞了,搞得我还得重发一遍,大家自己找原steam指南吧,之前吧主也搬运过,请给作者个好评或者点数)
一楼水一下,终于放假有时间发帖子了,游戏是个好游戏,自由度也很高,非常经典的RPG,但是节奏不适合我这种不开修改器或者不打Mod就不会玩的老登。而且由于引擎原因,CE好像不好找内存地址,所幸发现了吧主发的搬运指南,里面有关于修改的一些内容,我就整理一下分享出来
废话不多说直接实操:
1.首先找到 游戏目录文件夹(有Game.exe执行文件的那个)/game/js/game,这时会发现两个文件,一个union.js,一个modloader.js,记住这个文件夹。
2.在这个文件夹新建一个文本文件,修改文件名为mod_mult_exp.js(注意后缀得把.txt改成.js),然后用记事本打开就行(如果有装notepad减减,或者其他代码编辑器就更好了,直接用编辑器打开),完整复制以下代码,并保存即可。


IP属地:北京1楼2025-04-04 14:20回复
    第2步的代码在这里(两个表情之间的全部):

    /**
    这个文件作为mod注入游戏中,具体方式不了解,只是照葫芦画瓢
    如果使这个文件的mod生效,需要把以下代码添加到union.js这个文件最后:
    $(document).ready(function () {
    console.log("加载自定义代码");
    // 下面是mod具体的文件名,以mod_mult exp.js为例:
    var files = ['mod_mult_exp.js'];
    for (var file of files) {
    var script = document.createElement('script');
    script.setAttribute('src', './js/game/' + file);
    script.onload = function () {
    console.log(`${file} has been injected!`);
    }
    document.head.appendChild(script);
    }
    });
    */
    //以下是经验直接倍乘修改代码,不确定是否工作,话说java需要在函数语句末加分号吗?
    function hook_prototype(obj, method_name, hook) {
    // Save the original method
    const original = obj.__proto__[method_name];
    // Replace the original method with the hook
    obj.__proto__[method_name] = function(...args) {
    // Log the method call
    console.log(`Calling ${method_name} with arguments:`, args);
    // If the hook is undefined, null or otherwise falsey, call the original method instead
    if (typeof hook === 'function') {
    hook(this, original, args);
    } else {
    original.apply(this, args);
    }
    };
    }
    function hookIntoGame() {
    console.log('This is from the modloader, we\'re loaded!');
    // Using prototype pollution to hook into the game
    hook_prototype(tWgm.tGameCharactor, 'addExp', function(self, original, args) {
    // 检查是否是玩家或主要队伍成员
    if (args[0].teamId && args[0].teamId === "player") {
    //这里修改想要的经验倍数,下例为100倍
    args[3] *= 100;
    }
    // Call the original method with the modified arguments
    original.apply(self, args);
    });
    }
    // Enable native logging
    tWgm.isL = true;
    setTimeout(hookIntoGame, 1000);


    IP属地:北京2楼2025-04-04 14:22
    回复
      2025-08-06 16:56:26
      广告
      不感兴趣
      开通SVIP免广告
      我们继续:
      3.这时该文件夹下有三个文件了,union.js、modloader.js、mod_mult_exp.js,此时先备份一个union.js(一定一定复制备份一个,防止改完游戏打不开了),然后用记事本或代码编辑器打开union.js,直接拉到最下面,回车另起一行,将下面的代码粘贴过去(两个表情之间的全部):

      $(document).ready(function () {
      console.log("加载自定义代码");
      // 下面是mod具体的文件名,以mod_get items.js为例:
      var files = ['mod_mult exp.js'];
      for (var file of files) {
      var script = document.createElement('script');
      script.setAttribute('src', './js/game/' + file);
      script.onload = function () {
      console.log(`${file} has been injected!`);
      }
      document.head.appendChild(script);
      }
      });


      IP属地:北京3楼2025-04-04 14:27
      收起回复
        4.保存刚才修改的union.js,这时经验倍乘的效果再开游戏应该就已经生效了。
        具体需要几倍经验,可以修改第二步的代码里:
        if (args[0].teamId && args[0].teamId === "player") {
        //这里修改想要的经验倍数,下例为100倍
        args[3] *= 100;
        }
        把args[3] *=后面的值改为你想要的倍数即可。


        IP属地:北京4楼2025-04-04 14:30
        回复
          接下来继续说添加消耗品的mod
          5.再在该文件夹下新建一个txt文本文件,修改文件名为mod_get_items.js(注意后缀改为.js),保存后用记事本或代码编辑器打开,将以下代码粘贴过去并保存即可(两个表情之间的全部,帖子太长了,中间用分开):

          /**
          * Simple ModLoader for Isekainosouzousha (異世界の創造者)
          *
          * This modloader is NOT supported by the original developers of the game and is
          * only made out of love and enjoyment for the game.
          *
          * Add this snippet to the union.js file to load the modloader:
          ```
          $(document).ready(function () {
          console.log("We're now running custom code");
          // Load a new .js file named modloader.js
          var files = ['modloader.js'];
          for (var file of files) {
          var script = document.createElement('script');
          script.setAttribute('src', './js/game/' + file);
          script.onload = function () {
          console.log(`${file} has been injected!`);
          }
          document.head.appendChild(script);
          }
          });
          以上是原注释,下面是翻译和个人理解:
          这个文件作为mod注入游戏中,具体方式不了解,只是照葫芦画瓢
          如果使这个文件的mod生效,需要把以下代码添加到union.js这个文件最后:
          $(document).ready(function () {
          console.log("加载自定义代码");
          // 下面是mod具体的文件名,以mod_get items.js为例:
          var files = ['mod_get_items.js'];
          for (var file of files) {
          var script = document.createElement('script');
          script.setAttribute('src', './js/game/' + file);
          script.onload = function () {
          console.log(`${file} has been injected!`);
          }
          document.head.appendChild(script);
          }
          });
          ```
          */
          //以下是添加物品代码,实测可用
          (function() {
          // Create a modloader object in the global scope if none exists yet
          if ((typeof window.tModLoader) !== 'undefined') {
          // We already have a modmenu object, so we can exit this script
          console.error('Modloader already exists in the global scope');
          console.error('Please make sure to only include this script once');
          console.error('Exiting script...');
          return;
          }
          // Create a new mod loader object
          // Using prototypes to make it easier to use
          function tModLoader() {
          // Initialize the modmenu object
          this.init();
          }
          tModLoader.prototype = {
          init: function() {
          // Initialize the modmenu object
          this.version = (0, 1, 0);
          },
          /**
          * Create a new hook into an object's method using prototype pollution
          *
          * When overriding the method, please make sure to call the original method from within the hook
          * @param {*} obj
          * @param {string} method_name
          * @param {function} hook
          */
          hook_prototype: function(obj, method_name, hook) {
          // Save the original method
          const original = obj.__proto__[method_name];
          // Replace the original method with the hook
          obj.__proto__[method_name] = function(...args) {
          // Log the method call
          console.log(`Calling ${method_name} with arguments:`, args);
          // If the hook is undefined, null or otherwise falsey, call the original method instead
          try {
          if (typeof hook === 'function') {
          return hook(this, original, args);
          } else {
          return original.apply(this, args);
          }
          } catch (err) {
          // Either we screwed something up or the game just throws an error with the function
          // naturally. Either way we don't want the game to just crash because of it.
          console.error(err);
          }
          }
          },


          IP属地:北京5楼2025-04-04 14:33
          回复

            /**
            * Logs all method calls of the object
            * @param {*} obj
            */
            hook_all_prototypes: function(obj) {
            // Hook all prototypes of the object to log the method calls
            for (let method_name of Object.getOwnPropertyNames(obj.__proto__)) {
            const original = obj.__proto__[method_name];
            obj.__proto__[method_name] = function(...args) {
            console.log(`Calling ${method_name} with arguments:`, args);
            return original.apply(this, args);
            }
            }
            },
            /**
            * Some functions may throw errors and thus crash the game. This function
            * insulates the function by catching the error and logging it instead.
            *
            * This is not a substitute for proper error handling, but it can be useful
            * for quick debugging.
            *
            * A default return value can be provided in case the function would normally return something.
            * @param {*} obj
            * @param {string} method_name
            * @param {*} default_return
            */
            make_safe: function(obj, method_name, default_return) {
            // Insulate a function, using prototype pollution to make it safe
            const original = obj.__proto__[method_name];
            obj.__proto__[method_name] = function(...args) {
            try {
            return original.apply(this, args);
            } catch (err) {
            console.error(err);
            // If this returned something normally we now have a problem, maybe.
            return default_return;
            }
            }
            },
            /**
            * Once the game is loaded, call the callback(s) to execute.
            * The callbacks will only be executed ONCE
            * @param {function} callback
            */
            once_loaded: function(callback) {
            this.loaded_callbacks = this.loaded_callbacks || [];
            this.loaded_callbacks.push(callback);
            console.log('Added callback to loaded_callbacks:', callback);
            },
            call_loaded_callbacks: function() {
            console.log('Calling loaded_callbacks:', this.loaded_callbacks);
            this.loaded_callbacks = this.loaded_callbacks || [];
            for (var callback of this.loaded_callbacks) {
            callback(this);
            }
            }
            };
            // Make the modloader object available in the global scope
            window.tModLoader = new tModLoader();
            // Log that the modloader is loaded
            console.log('Modloader loaded:', window.tModLoader);
            })();
            /*
            Example usage of the modloader
            ------------------------------
            Patch a couple of problematic functions once the game is loaded.
            These patches are purely bug fixes and do not add any new functionality.
            */
            window.tModLoader.once_loaded(function(modloader) {
            console.log('The game has been loaded, patching some functions now...');
            // Patch some functions here to provide additional functionality
            // tWgm.tGameItem.getItemName has a bug where it sometimes throws an error.
            // Adding a default return value to make it safe
            modloader.make_safe(tWgm.tGameItem, 'getItemName', 'Unknown Item');
            });
            window.tModLoader.once_loaded(function(modloader) {
            console.log('This is from the modloader, we\'re loaded!');
            // Using prototype pollution to hook into the game
            modloader.hook_prototype(tWgm.tGameMenu, 'viewMenu');
            modloader.hook_prototype(tWgm.tGameCharactor, 'addItem')
            //hook_all_prototypes(tWgm.tGameCharactor);
            // Hook tGameMenu prototypes to potentially make our own menu
            modloader.hook_prototype(tWgm.tGameMessageWindow, 'viewMessageWindow', function(self, original, args) {
            // Attempt to isolate the escape menu
            var answers = args[0].answers;
            // Check if we have an option for 'Return to title screen'
            var isMainMenu = answers.find(answer => answer.message === tWgm.tGameTalkResource.talkData.system.gototitle) !== undefined;
            isMainMenu &&= answers.find(answer => answer.message === tWgm.tGameTalkResource.talkData.system.itemmiru) !== undefined;
            // If we have the main menu, we can potentially replace it with our own.
            // For now just add a dummy button which logs a message
            if (isMainMenu) {
            answers.push({
            message: '打开mod',
            callBack: function() {
            // Show a new menu
            var answers = [];
            // Add a dummy button
            answers.push({
            message: '返回',
            callBack: function() {
            console.log('Dummy button pressed');
            tWgm.tGameRoutineMap.setFrameAction(tWgm);
            }
            });
            answers.push({
            message: '改数的调用窗口,无效果',
            callBack: function() {
            tWgm.tGameSoundResource.play('select');
            tWgm.tGameNumWindow.viewNumWindow({
            label: tWgm.tGameTalkResource.talkData.system.ikutsuoku,
            startNum: 1,
            minNum: 1,
            maxNum: 999999,
            isSelectSound: false,
            selectCallBack: function(num) {
            console.log('Selected number:', num);
            tWgm.tGameRoutineMap.setFrameAction(tWgm);
            },
            cancelCallBack: function() {
            console.log('Cancelled number selection');
            tWgm.tGameRoutineMap.setFrameAction(tWgm);
            }
            });
            }
            });
            answers.push({
            message: '获得物品',
            callBack: function () {
            // Go through the object `tWgm.tGameItem.masterData.items` to get all items
            var all_items = [];
            // Structure of `tWgm.tGameItem.masterData.items`:
            // { item_id: [ some_data, some_data, ... ], ... }
            for (var item_id in tWgm.tGameItem.masterData.items) {
            var master_data = tWgm.tGameItem.masterData.items[item_id];
            var item_data = tWgm.tGameItem.createItem({
            itemId: item_id,
            isShikibetsu: true, // Is identified item
            isNoroi: false // Is cursed item
            });
            all_items.push(item_data);
            }
            tWgm.tGameItemWindow.viewItemWindow({
            label: "这个是对话栏标签,随便写点什么",
            items: all_items,
            isSelectClear: !1,
            isViewPrice: !1,
            isSelectSound: !1,
            isSell: !1,
            selectItemCallBack: function(index) {
            console.log('Selected item index:', index);
            var item = all_items[index];
            // Add the item to the player inventory?!
            // tWgm.tGameCharactor.addItem("player", item, 1);
            tWgm.tGameNumWindow.viewNumWindow({
            label: tWgm.tGameTalkResource.talkData.system.ikutsuoku,
            startNum: 1,
            minNum: 1,
            maxNum: 999999,
            isSelectSound: false,
            selectCallBack: function(num) {
            console.log('Selected number:', num);
            // If it's a money item, we need to use addMoney
            if (item[1] >= 99999990001) {
            tWgm.tGameCharactor.addMoney(tWgm.tGameCharactor.charas.player, num, -1, item[1]);
            } else {
            item[10] = num;
            tWgm.tGameCharactor.addItem("player", item, 1);
            }
            tWgm.tGameItemWindow.clear();
            tWgm.tGameRoutineMap.setFrameAction(tWgm);
            },
            cancelCallBack: function() {
            console.log('Cancelled number selection');
            }
            });
            },
            cancelCallBack: function() {
            console.log('Cancelled item selection');
            tWgm.tGameRoutineMap.setFrameAction(tWgm);
            },
            bottomData: tWgm.tGameItemWindow.getCharactorBottomData(tWgm.tGameCharactor.charas.player)
            });
            }
            })
            // Display the ModMenu
            tWgm.tGameMessageWindow.viewMessageWindow({
            selectedIndex: 0,
            answers: answers,
            viewItemMaxNum: 12,
            position: [null, args[0].position[1]],
            cancelCallBack: function() {
            console.log('ModMenu closed due to `cancelCallBack`');
            tWgm.tGameRoutineMap.setFrameAction(tWgm);
            },
            });
            }
            });
            }
            original.apply(self, args);
            });
            });
            // Enable native logging
            tWgm.isL = true;
            // Wait for the game to load...
            setTimeout((() => window.tModLoader.call_loaded_callbacks()), 1000);


            IP属地:北京6楼2025-04-04 14:34
            回复
              6.保存刚才复制到mod_get_items.js过去的代码,再次打开union.js文件,和第3步一样,另起一行,将下面的代码粘到最后面(两个表情之间的全部):

              (document).ready(function () {
              console.log("加载自定义代码");
              // 下面是mod具体的文件名,以mod_get items.js为例:
              var files = ['mod_get_items.js'];
              for (var file of files) {
              var script = document.createElement('script');
              script.setAttribute('src', './js/game/' + file);
              script.onload = function () {
              console.log(`${file} has been injected!`);
              }
              document.head.appendChild(script);
              }
              });


              IP属地:北京7楼2025-04-04 14:37
              回复
                7.保存修改的union.js并退出,大功告成,现在再进入游戏,应该就有经验倍率和刷物品的效果了,下面是一些预览。
                刷消耗品可以通过x键打开菜单,翻到最后一页,有个[打开mod],选择后下级菜单选最下面的[获得物品],就是刷消耗品的界面了。




                IP属地:北京8楼2025-04-04 14:45
                回复
                  2025-08-06 16:50:26
                  广告
                  不感兴趣
                  开通SVIP免广告
                  经验倍率是否生效,可以随便吃个东西,我这里吃了个柿子,可以看到抗魔和魅力都提升了很多(我改了100倍经验,×50个星星)


                  IP属地:北京9楼2025-04-04 14:47
                  回复
                    当然,不想一点一点粘贴代码,我也分享一下改好的文件,直接放在 游戏目录文件夹(有Game.exe执行文件的那个)/game/js/game 就行,替换掉原来的union.js【特别注意,替换之前备份自己的union.js,我的游戏版本号是1.5.4.0,如果不一致大概率打不开游戏了,版本号不一致的话不能直接替换,看一下上面的楼层里教程,相应修改自己游戏文件的代码就行】
                    通过网盘分享的文件:异世界创造者mod
                    链接: https://pan.baidu.com/s/1nncQiZEKhxeqReQhgz1ugw?pwd=cgyc 提取码: cgyc
                    --来自百度网盘超级会员v6的分享


                    IP属地:北京10楼2025-04-04 14:55
                    回复
                      好好好,收下了


                      IP属地:福建来自Android客户端11楼2025-04-04 18:15
                      回复
                        没有modloader.js怎么办


                        IP属地:湖北12楼2025-04-18 11:17
                        收起回复

                          修改了union.js之后启动游戏就失败了,闪一下就一直黑屏,版本是1.5.5.0,在原文件上改的


                          IP属地:湖南13楼2025-05-11 14:47
                          收起回复
                            很好用,谢谢楼主分享,可惜物品调用里没技巧之灯,这个太难弄了,只有每年庆典上能偷一个


                            IP属地:四川来自Android客户端14楼2025-05-12 11:12
                            收起回复
                              2025-08-06 16:44:26
                              广告
                              不感兴趣
                              开通SVIP免广告
                              modloader.js这个文件可以分享一下吗


                              IP属地:安徽15楼2025-06-02 22:59
                              回复