Site icon May's Notes

【楓之谷私服】v120 輪迴碑石

新增輪迴碑石怪物

首先用 HaRepacker 打開 Mob.wz,隨意新增一個 Image,比如我是新增 999026.img,內容節點複製 9990013.img 的,然後將 hit1 整個節點刪除。

info 節點的內容 :

bodyAttack: 0
elemAttr: S1H3
acc: 150
boss: 1
eva: 30
exp: 0
level: 200
MADamage: 0
maxHP: 5000000
maxMP: 5000
MDDamage: 0
PADamage: 0
PDDamage: 0
pushed: 3000
removeAfter: 300 (以秒為單位, 自行設定)
speed: -20
summonType: 0
undead: 0

新增輪迴消耗道具

接著用 HaRepacker 打開 Item.wz,進入 Consume (消耗) 節點,找到 0210.img 雙擊展開,隨意新增一個 sub 節點,我這邊以 02109013 作為示範,內容節點直接複製 02101081 就可以。

如果以上步驟都做完,在遊戲中下指令 !item 2109013 獲取輪迴之後使用,地圖上應該就會出現輪迴,如果你的輪迴有被叫出來就可以繼續下面的步驟了。

順帶一提,String.wz 也要加上 2109013 的節點,不然你的輪迴消耗道具是不會有名字和描述的。

判斷地圖上有輪迴就加速怪物生長

有了輪迴怪物和輪迴召喚包後,我們還需要修改 SRC 來判斷地圖上是否有輪迴,如果有就將該地圖的怪物數量乘以你指定的倍率,但如果是特殊地圖或者有 BOSS 的地圖就不會生效。

打開 SRC,在 server.maps 裡新增 MobConstants.java,內容如下:

/*
 * 輪迴碑石
 */
package server.maps;

import server.maps.MapleMap;
import server.maps.MapleMapObject;
import server.life.MapleMonster;
import constants.MapConstants;

public class MobConstants {
    public static int [] REINCARNATION_MOB = new int[]{ 9990026, 2 }; // 輪迴怪物代碼, 生怪數量倍率

    public static int isMonsterSpawn(MapleMap map) {
        int addition = 1;
        if (MapConstants.isBossMap(map.getId()) || MapConstants.isEventMap(map.getId())) { // 判斷是否為特殊地圖, 輪迴不會在特殊地圖生效
            return 1;
        }
        for (MapleMapObject obj : map.getAllMonstersThreadsafe()) { // 判斷地圖有boss, 回傳倍率1
            final MapleMonster mob = (MapleMonster) obj;
            if (mob.getStats().isBoss() && !isReincarnationMob(mob.getId())) {
                return 1;
            }
        }
        if (map.getMonsterById(REINCARNATION_MOB[0]) != null) { // 判斷是否有輪迴
            addition *= REINCARNATION_MOB[1]; // 乘以倍率
        }
        return addition;
    }
    
    public static boolean isReincarnationMob(int mobid) { // 判斷是否為輪迴怪物
        if (REINCARNATION_MOB[0] == mobid) {
            return true;
        }
        return false;
    }
    
    public static boolean isSpawnSpeed(MapleMap map) {
        if (map.getMonsterById(REINCARNATION_MOB[0]) != null) {
            return true;
        }
        return false;
    }

}

接著打開 server.maps.MapleMap.java,在最上方引入 MobConstants

import server.maps.MobConstants;

接著在 MapleMap.java 中 ctrl + f 搜尋「public void respawn」,將 numShouldSpawn 改為以下程式碼:

final int numShouldSpawn = monsterSpawn.size() * MobConstants.isMonsterSpawn(this) - spawnedMonstersOnMap.get(); // 輪迴倍率
// final int numShouldSpawn = monsterSpawn.size() - spawnedMonstersOnMap.get();

完整的 respawn 函式程式碼為:

public void respawn(final boolean force) {
        lastSpawnTime = System.currentTimeMillis();
        if (force) { //cpq quick hack
            final int numShouldSpawn = monsterSpawn.size() * MobConstants.isMonsterSpawn(this) - spawnedMonstersOnMap.get(); // 輪迴倍率
            // final int numShouldSpawn = monsterSpawn.size() - spawnedMonstersOnMap.get();

            if (numShouldSpawn > 0) {
                int spawned = 0;
    
                for (Spawns spawnPoint : monsterSpawn) {
                    spawnPoint.spawnMonster(this);
                    spawned++;
                    if (spawned >= numShouldSpawn) {
                        break;
                    }
                }
            }
        } else {
            final int numShouldSpawn = maxRegularSpawn * MobConstants.isMonsterSpawn(this) - spawnedMonstersOnMap.get(); // 輪迴倍率
            // final int numShouldSpawn = maxRegularSpawn - spawnedMonstersOnMap.get();
            if (numShouldSpawn > 0) {
                int spawned = 0;
    
                final List<Spawns> randomSpawn = new ArrayList<Spawns>(monsterSpawn);
                Collections.shuffle(randomSpawn);
    
                for (Spawns spawnPoint : randomSpawn) {
                    if (spawnPoint.shouldSpawn() || GameConstants.isForceRespawn(mapid)) {
                        spawnPoint.spawnMonster(this);
                        spawned++;
                    }
                    if (spawned >= numShouldSpawn) {
                        break;
                    }
                }
            }
        }
    }

繼續在 MapleMap.java 中搜索 canSpawn,將 function 內容改為:

public final boolean canSpawn() {
    createMobInterval = (short) (MobConstants.isSpawnSpeed(this) ? 0 : 9000); // 有輪迴時怪物重生時間間隔為 0
    return lastSpawnTime > 0 && isSpawns && lastSpawnTime + createMobInterval < System.currentTimeMillis();
    // return true;
}

加上輪迴限制

如果已經有玩家在地圖上放了輪迴就不能再放。

1.打開 server.life.MapleMonsterStats.java 最上面 private int 處加上 ,SpawnChrId

接著在最下面加上:

public int getSpawnChrId() {
   return SpawnChrId;
}

2.打開 server.life.MapleMonster.java 最下面加上:

public final int getSpawnChrid(){
   return stats.getSpawnChrId();
}

3.在 client.MapleCharacter.java 最下方加上:(這個函式是用來判斷地圖上是否有輪迴)

public boolean isReincarnationMob() {
        for (MapleMonster monster : getMap().getAllMonster()) {
            if (monster.getId() == 9990026 && monster.getSpawnChrid() != this.getId()) { // 輪迴 mob id
                return true;
            }
        }
        return false;
    }

4.打開 handling.channel.handlerInventoryHandler.java,加上 UseSummonBagNotCSP 函式:

public static int UseSummonBagNotCSP(int itemId) {
        int result = 0;
        switch (itemId) {
            case 2109013: // 輪迴道具 ID
                result = 1;
                break;
        }
        return result;
}

5.接著搜索 UseSummonBag,在這段程式碼

if (c.getPlayer().isGM() || !FieldLimitType.SummoningBag.check(chr.getMap().getFieldLimit())) {
   final List<Pair<Integer, Integer>> toSpawn = MapleItemInformationProvider.getInstance().getSummonMobs(itemId);

   if (toSpawn == null) {
       c.getSession().write(MaplePacketCreator.enableActions());
       return;
    }

下方加上:

   if (UseSummonBagNotCSP(toUse.getItemId()) > 0) {
       int result = UseSummonBagNotCSP(toUse.getItemId());
       if (result > 0) {
          if (chr.isReincarnationMob()) {
              switch (result) {
                  case 1: {
                      chr.dropMessage("地圖上有人施放了輪迴");
                      break;
                   }
              }
              c.getSession().write(MaplePacketCreator.enableActions());
              return;
          }
       }
   }
   //....

完整的 UseSummonBag 為:

public static final void UseSummonBag(final SeekableLittleEndianAccessor slea, final MapleClient c, final MapleCharacter chr) {
        if (!chr.isAlive()) {
            c.getSession().write(MaplePacketCreator.enableActions());
            return;
        }
        c.getPlayer().updateTick(slea.readInt());
        final byte slot = (byte) slea.readShort();
        final int itemId = slea.readInt();
        final IItem toUse = chr.getInventory(MapleInventoryType.USE).getItem(slot);

        if (toUse != null && toUse.getQuantity() >= 1 && toUse.getItemId() == itemId) {

            MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, slot, (short) 1, false);

            if (c.getPlayer().isGM() || !FieldLimitType.SummoningBag.check(chr.getMap().getFieldLimit())) {
                final List<Pair<Integer, Integer>> toSpawn = MapleItemInformationProvider.getInstance().getSummonMobs(itemId);

                if (toSpawn == null) {
                    c.getSession().write(MaplePacketCreator.enableActions());
                    return;
                }
                if (UseSummonBagNotCSP(toUse.getItemId()) > 0) {
                    int result = UseSummonBagNotCSP(toUse.getItemId());
                    if (result > 0) {
                        if (chr.isReincarnationMob()) {
                            switch (result) {
                                case 1: {
                                    chr.dropMessage("已經有玩家施放了輪迴");
                                    break;
                                }
                            }
                            c.getSession().write(MaplePacketCreator.enableActions());
                            return;
                        }
                    }
                }
                MapleMonster ht;
                int type = 0;

                for (int i = 0; i < toSpawn.size(); i++) {
                    if (Randomizer.nextInt(99) <= toSpawn.get(i).getRight()) {
                        ht = MapleLifeFactory.getMonster(toSpawn.get(i).getLeft());
                        chr.getMap().spawnMonster_sSack(ht, chr.getPosition(), type);
                    }
                }
            }
        }
        c.getSession().write(MaplePacketCreator.enableActions());
    }
Exit mobile version