天堂2单机论坛

 找回密码
 立即注册
查看: 43|回复: 0

【教程】10.1mobius按怪等级批量加掉落的邪修大法

[复制链接]
  • TA的每日心情
    无聊
    昨天 13:09
  • 签到天数: 10 天

    [LV.3]偶尔看看II

    2

    主题

    18

    帖子

    73

    积分

    正式会员

    Rank: 2

    积分
    73
    发表于 前天 23:25 | 显示全部楼层 |阅读模式
    起因
    今天在折腾特殊制作,发现亚丁精髓的材料老是打不出来。于是查了一下掉落,好家伙。官方设定中只有少数几个怪掉落,还只掉其中一两样。


    这怎么能愉快地玩耍,于是我决定自己加。但是每个怪单独配置,上千个怪估计先死的是我。
    于是。。。。。。。一个邪恶的念头悄悄泛起了涟漪。


    一句话
    掉落判定不在一个 XML 里,所有怪、所有死法的掉落最后都要走同一个方法:
    Attackable.doItemDrop(NpcTemplate npcTemplate, Creature mainDamageDealer)
    在它的开头插一段十几行的代码,就能让所有符合条件的怪(哪怕以后再新加自制怪也不用再重复操作了)多掉东西——不用动任何 npc XML,也不用一只只怪手工加。

    掉落管线data/stats/npcs/<区间>.xml    原码掉落表写在这里:<dropLists><drop><group chance="…"><item id="…" …>        │  开机时由 NpcData 解析成内存里的掉落表        ▼NpcTemplate.calculateDrops(DropType.DROP, npc, killer)    源码掉落表的「判定」在这里(机率、数量、掉宝倍率都在这层)        │        ▼Attackable.doItemDrop(NpcTemplate, Creature)      ←  所有怪、所有死法的唯一总出口        │        ├─ player.doAutoLoot(this, drop)   自动拾取 → 直接进背包        └─ dropItem(player, drop)          掉在地上,等人捡
    你要找的就是最后那个「总出口」。它同时是每一只怪的出口(正常打死、宝箱怪、离线挂机刷的怪……最后都汇到这里),所以挂在这里 = 一处改、全局生效。

    好!开始动手!
    第 1 步:确认你版本里的方法签名与插入点grep -n "doItemDrop" "<你的源码>/java/org/l2jmobius/gameserver/entity/actor/Attackable.java"

    10.1 上游 master 的方法长这样(// ★ 是注释):
    public void doItemDrop(NpcTemplate npcTemplate, Creature mainDamageDealer){        if (mainDamageDealer == null)        {                return;                       // ★ 额外掉落必须插在【这个 return 之后】        }                final Player player = mainDamageDealer.asPlayer();                // 最后一刀不是玩家就不掉(除非是假人)        if (player == null)        {                if (mainDamageDealer.isFakePlayer() && FakePlayersConfig.FAKE_PLAYER_CAN_DROP_ITEMS)                {                        final Collection<ItemHolder> deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer);                        if (deathItems != null)                        {                                for (ItemHolder drop : deathItems)                                {                                        // ……自动拾取判断……                                        dropItem(mainDamageDealer, drop);   // 假人/离线挂机:掉在地上                                }                                deathItems.clear();                        }                }                return;                       // ★ …插在这行【之前】,才能同时覆盖真人 + 假人        }                CursedWeaponsManager.getInstance().checkDrop(this, player);        // ……以下原厂逻辑(含 isSpoiled() 的 SPOIL 掉落、真人路径的 doAutoLoot / dropItem)……}
    插入位置口诀:mainDamageDealer == null 的检查之后、asPlayer() 之前。
    插在 null 检查之前 ⇒ killer 为 null 时会 NPE,连原厂掉落一起整批吞掉(而且日志可能什么都不报)。插在方法最后 ⇒ 假人/离线挂机走的是上面那个 return,永远拿不到额外掉落。

    第 2 步:贴上这段代码
    需求示例:所有 Lv.80 以上的普通怪,额外 5% 掉 1~2 个「强化结晶」。9552 只是个占位,换成你自己要掉的道具 id。
                    // ===== 全局额外掉落(示例:Lv.80+ 普通怪 5% 掉 1~2 个)=====                final int bonusItemId = 9552;                          // ← 换成你要掉的道具 id                final boolean bonusTarget = npcTemplate.isType("Monster") // 只对普通怪                                && !isRaid()                                     // 排除首领/狩猎首領                                && (npcTemplate.getId() < 900000)                // 排除高 id 段的自定义 NPC(如果有做自定义)                                && (getLevel() >= 80);                           // 等级门槛                if (bonusTarget && (Rnd.get(10000) < 500))             // 500/10000 = 5.00%(0.01% 粒度)                {                        final int bonusCount = 1 + Rnd.get(2);             // 1~2 个                        final ItemHolder bonus = new ItemHolder(bonusItemId, bonusCount);                        final Player bonusOwner = mainDamageDealer.asPlayer();                        if (bonusOwner != null)                        {                                bonusOwner.doAutoLoot(this, bonus);            // 真人:走自动拾取流程,直接进背包                        }                        else                        {                                dropItem(mainDamageDealer, bonus);             // 假人/离线挂机:掉在地上                        }                }                // ===== 示例结束 =====
    用的全是这个类里现成的东西,不用加 import:
    名称出处作用
    npcTemplate方法参数这只怪的模板,类型/id/等级都从它拿
    npcTemplate.isType("Monster")NpcTemplate判断是不是普通怪(部分版本写成 "Monster".equals(npcTemplate.getType()))
    isRaid()Attackable是不是首领;本版还有 _isRaid 字段
    npcTemplate.getId() / getLevel()NpcTemplate / Npc排除 id 段、做等级阶梯
    Rnd.get(n)org.l2jmobius.commons.util.Rnd0~n-1 随机数(本文件已 import)
    new ItemHolder(id, count)entity/item/holders/ItemHolder掉落物的「id + 数量」载体(本文件已 import)
    mainDamageDealer.asPlayer()Creature不是玩家(假人/召唤物)会返回 null
    doAutoLoot(this, holder)Player按自动拾取规则发道具
    dropItem(who, holder)Npc把道具掉在地上

    编译报「找不到符号」时:Rnd / ItemHolder 补 import;Player 与 Attackable 同包,本不需要 import。

    第 3 步:编译javac -g -encoding UTF-8 \  -cp "<你的服务端>/libs/GameServer.jar:<你的服务端>/libs/*" \  -d out "<你的源码>/java/org/l2jmobius/gameserver/entity/actor/Attackable.java"
    • Windows 的 classpath 分隔符是 ;,Linux/macOS 是 :(写错了就是一堆「找不到符号」)。
    • libs/* 要把整个 jar 目录带上,GameServer.jar 只是其中一个。
    • -g 不能省:原厂 class 带 LocalVariableTable,你重编时不带,字节码的局部变量信息就对不上(做热替换时尤其容易出问题)。
    • 产物:out/org/l2jmobius/gameserver/entity/actor/Attackable.class

    让它生效

    1) 停服2) 备份3) 不要直接对运行中的 jar 打包(会被锁)——先复制副本改,再整档盖回cp libs/GameServer.jar libs/GameServer.jar.tmpcd outjar uf ../libs/GameServer.jar.tmp org/l2jmobius/gameserver/entity/actor/Attackable.classcd ..cp libs/GameServer.jar.tmp libs/GameServer.jar4) 三条校验jar tf libs/GameServer.jar | wc -l                      # 条目数应与备份一致cp libs/GameServer.jar /tmp/x.jar && unzip -p /tmp/x.jar org/l2jmobius/gameserver/entity/actor/Attackable.class | wc -cjavap -c -p -cp out org.l2jmobius.gameserver.entity.actor.Attackable | grep -n "9552\|10000"5) 启服,看日志:Server loaded in … seconds,没有 exception













    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|监狱|天堂2单机论坛 ( 粤ICP备20030366号 )

    GMT+8, 2026-10-10 06:52 , Processed in 0.053938 second(s), 22 queries .

    Powered by Discuz! X3.4

    © 2001-2023 Discuz! Team.

    快速回复 返回顶部 返回列表