L2JMobius

Fafurion Client Drop Spoil Patch generator

rocoder · 1 · 779

Offline rocoder

  • Vassal
  • *
    • Posts: 7
After some work I managed to generate the right files in order to have in client drop spoil patch for all the monsters that are in npc xmls. I will provide hint's for whoever want's to use it but I wont support for code change or integration in each project .... my idea was to integrate it temporary in game server because Npc template and rates are already available ... npcgrp skillgrp and skillnames has to be manually edited with the the content generated by this code


I expect that each server has his own customizations so.... probably you will have to adapt the code a little

Code: [Select]
@@ -0,0 +1,370 @@
package org.l2jmobius.gameserver;

import org.l2jmobius.Config;
import org.l2jmobius.gameserver.data.ItemTable;
import org.l2jmobius.gameserver.data.xml.NpcData;
import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate;
import org.l2jmobius.gameserver.model.holders.DropGroupHolder;
import org.l2jmobius.gameserver.model.item.ItemTemplate;

import java.io.*;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class DropSpoilPatcher {
    private static DropSpoilPatcher instance = null;
    private final int startSkillTxtId = 36311;
    private final int dropSkillTxtId = 36309;
    private final int spoilSkillTxtId = 36310;
    private final DecimalFormat decimalFormat = new DecimalFormat("#." + "0".repeat(1));
    private final DecimalFormat decimalFormat0 = new DecimalFormat("0." + "0".repeat(5));
    private final String skillTxtAtomicPattern = "skill_txt_begin\ttext=[???]\tindex=###\tskill_txt_end\n";

    private final int startSkillId = 56000;
    private final String skillDropAtomicPattern = "skill_begin\tskill_id=???\tskill_level=1\tskill_sublevel=0\tname=36309\tdesc=###\tdesc_param=3\tenchant_name=3\tenchant_name_param=3\tenchant_desc=3\tenchant_desc_param=3\tskill_end\n";
    private final String skillSpoilAtomicPattern = "skill_begin\tskill_id=???\tskill_level=1\tskill_sublevel=0\tname=36310\tdesc=###\tdesc_param=3\tenchant_name=3\tenchant_name_param=3\tenchant_desc=3\tenchant_desc_param=3\tskill_end\n";

    private final String skillGrpDropAtomicPattern = "skill_begin\tskill_id=???\tskill_level=1\tskill_sublevel=0\ticon_type=13\tMagicType=0\toperate_type=2\tmp_consume=0\tcast_range=-1\tcast_style=0\thit_time=0.0\tcool_time=0.0\treuse_delay=0.0\teffect_point=0\tis_magic=0\torigin_skill=0\tis_double=0\tanimation={[None]}\tskill_visual_effect=[None]\ticon=[icon.skill0042]\ticon_panel=[None]\tdebuff=0\tresist_cast=0\tenchant_skill_level=0\tenchant_icon=[None]\thp_consume=0\trumble_self=-1\trumble_target=-1\tskill_end\n";
    private final String skillGrpSpoilAtomicPattern = "skill_begin\tskill_id=???\tskill_level=1\tskill_sublevel=0\ticon_type=13\tMagicType=0\toperate_type=2\tmp_consume=0\tcast_range=-1\tcast_style=0\thit_time=0.0\tcool_time=0.0\treuse_delay=0.0\teffect_point=0\tis_magic=0\torigin_skill=0\tis_double=0\tanimation={[None]}\tskill_visual_effect=[None]\ticon=[icon.skill0254]\ticon_panel=[None]\tdebuff=0\tresist_cast=0\tenchant_skill_level=0\tenchant_icon=[None]\thp_consume=0\trumble_self=-1\trumble_target=-1\tskill_end\n";

    private FileWriter file1, file2, file3;

    private Map<String, int[]> mapNpcNewSkills = new HashMap<>();

    private DropSpoilPatcher() {
        try {
            file1 = new FileWriter("SkillName-eu_1.txt");
            file2 = new FileWriter("SkillName-eu_2.txt");
            file3 = new FileWriter("Skillgrp.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static synchronized DropSpoilPatcher getInstance() {
        if (instance == null) {
            instance = new DropSpoilPatcher();
        }
        return instance;
    }

    public void writeToFile1(String data) throws IOException {
        file1.write(data + "\n");
    }

    public void writeToFile2(String data) throws IOException {
        file2.write(data + "\n");
    }

    public void writeToFile3(String data) throws IOException {
        file3.write( data + "\n");
    }

    public void closeFiles() throws IOException {
        file1.close();
        file2.close();
        file3.close();
    }

    // Example usage
    public void generateOutput() {
        try {
            writeToFile1(buildSkillText());
            writeToFile2(buildSkillName());
            writeToFile3(buildSkillGrp());

            updateNpcGrp();

            closeFiles();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void updateNpcGrp() {
        String inputFile1 = "Npcgrp.txt"; // Provide the path to your first input file
        String outputFile = "Npcgrp_New.txt"; // Output file where merged content will be saved

        LinkedHashMap<Long, String> npcMap = new LinkedHashMap<>();

        // Read and store lines from the first file using npc_id as the key
        try (BufferedReader reader1 = new BufferedReader(new FileReader(inputFile1));
             BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile))) {

            String line;
            while ((line = reader1.readLine()) != null) {
                long npcId = extractNpcId(line);

                if (mapNpcNewSkills.get(Integer.toString((int)npcId))!=null) {
                    int[] retrievedValues1 = mapNpcNewSkills.get(Integer.toString((int) npcId));

                    line = line.replace("property_list="+extractNpcPropList(line),
                            "property_list="+updateNpcPropList(extractNpcPropList(line), retrievedValues1[0], retrievedValues1[1]));
                }
                npcMap.putIfAbsent(npcId, line);
            }

            // Write merged content to the output file (in the order of the input file)
            for (String mergedLine : npcMap.values()) {
                writer.write(mergedLine);
                writer.newLine();
            }

            System.out.println("Files generated successfully!");

        } catch (IOException e) {
            System.err.println("Error: " + e.getMessage());
        }

    }

    private  long extractNpcId(String line) {
        String[] parts = line.split("\t");
        for (String part : parts) {
            if (part.startsWith("npc_id=")) {
                String npcIdStr = part.substring("npc_id=".length());
                return Long.parseLong(npcIdStr);
            }
        }
        return -1; // Invalid npc_id, handle this accordingly in your code
    }

    private  String extractNpcPropList(String line) {
        String[] parts = line.split("\t");
        for (String part : parts) {
            if (part.startsWith("property_list=")) {
                return part.substring("property_list=".length());
            }
        }
        return "{0}"; // Invalid npc_id, handle this accordingly in your code
    }

    private  String updateNpcPropList(String originalList, int skillid1, int skillid2) {
        System.out.println(originalList);
        // Check if the original list is empty
        boolean isEmptyList = originalList.equals("{}") || originalList.equals("{0}");

        // Parse the original list
        String[] parts = isEmptyList ? new String[0] : originalList.substring(1, originalList.length() - 1).split(";");

        // Extract existing IDs and levels
        StringBuilder result = new StringBuilder("{");
        for (int i = 0; i < parts.length; i += 2) {
            result.append(parts[i]).append(";").append(parts[i + 1]);
            if (i < parts.length - 2) {
                result.append(";");
            }
        }

        // Add new IDs and levels
        if (!isEmptyList) {
            result.append(";");
        }
        result.append(skillid1).append(";").append("1").append(";");
        result.append(skillid2).append(";").append("1").append("}");


        return result.toString();
    }

    private String buildSkillGrp() {
        StringBuilder s = new StringBuilder();

        int indexForSkill = startSkillId;

        for (int lvl = 1; lvl <= 85; lvl++) {
            List<NpcTemplate> list = NpcData.getInstance().getAllMonstersOfLevel(lvl);
            for (NpcTemplate npc : list) {
                if (!npc.isQuestMonster()) {
                    int[] values = {indexForSkill,indexForSkill+1};
                    mapNpcNewSkills.put(Integer.toString(npc.getId()),values);

                    s.append(buildNpcDropSkillGrp(indexForSkill));

                    indexForSkill++;
                    s.append(buildNpcSpoilSkillGrp(indexForSkill));

                    indexForSkill++;
                }
            }
        }

        return s.toString();
    }

    private String buildNpcDropSkillGrp(int indexForSkill) {
        return skillGrpDropAtomicPattern.replace("???", Integer.toString(indexForSkill));
    }

    private String buildNpcSpoilSkillGrp(int indexForSkill) {
        return skillGrpSpoilAtomicPattern.replace("???", Integer.toString(indexForSkill));
    }

    private String buildSkillName() {
        StringBuilder s = new StringBuilder();

        int index = startSkillTxtId;
        int indexForSkill = startSkillId;

        for (int lvl = 1; lvl <= 85; lvl++) {
            List<NpcTemplate> list = NpcData.getInstance().getAllMonstersOfLevel(lvl);
            for (NpcTemplate npc : list) {
                if (!npc.isQuestMonster()) {
                    s.append(buildNpcDropSkillName(index, indexForSkill));
                    index++;
                    indexForSkill++;
                    s.append(buildNpcSpoilSkillName(index, indexForSkill));
                    index++;
                    indexForSkill++;
                }
            }
        }

        return s.toString();
    }

    private String buildNpcDropSkillName(int index, int indexForSkill) {
        return skillDropAtomicPattern.replace("???", Integer.toString(indexForSkill)).replace("###", Integer.toString(index));
    }

    private String buildNpcSpoilSkillName(int index, int indexForSkill) {
        return skillSpoilAtomicPattern.replace("???", Integer.toString(indexForSkill)).replace("###", Integer.toString(index));
    }

    private String buildSkillText() {
        StringBuilder s = new StringBuilder();

        int index = startSkillTxtId;

        for (int lvl = 1; lvl <= 85; lvl++) {
            List<NpcTemplate> list = NpcData.getInstance().getAllMonstersOfLevel(lvl);
            for (NpcTemplate npc : list) {
                if (!npc.isQuestMonster()) {
                    s.append(buildNpcDropTxt(npc, index));
                    index++;
                    s.append(buildNpcSpoilTxt(npc, index));
                    index++;
                }
            }
        }

        return s.toString();
    }

    private String buildNpcSpoilTxt(NpcTemplate npc, int index) {
        StringBuilder s = new StringBuilder();

        if (npc.getSpoilList() != null) {
            for (int i = 0; i < npc.getSpoilList().size(); i++) {
                String name = ItemTable.getInstance().getTemplate(npc.getSpoilList().get(i).getItemId()).getName();
                String minMax = npc.getSpoilList().get(i).getMin() + " - "
                        + (int) Math.floor(npc.getSpoilList().get(i).getMax() * Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER);
                double chance = npc.getSpoilList().get(i).getChance() * Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER;
                String chanceS;
                if (chance < 0.00001) {
                    chanceS = "<0.00001%%";
                } else if (chance < 1) {
                    chanceS = decimalFormat0.format(chance) + "%%";
                } else if (chance >= 100) {
                    chanceS = "99.0%%";
                } else {
                    chanceS = decimalFormat.format(chance) + "%%";
                }

                s.append(name + "   " + minMax + "   " + chanceS + "\\n");

            }
        }

        return skillTxtAtomicPattern.replace("???", s.toString()).replace("###", Integer.toString(index));
    }

    private String buildNpcDropTxt(NpcTemplate npc, int index) {
        StringBuilder s = new StringBuilder();


        if (npc.getDropList() != null) {
            for (int i = 0; i < npc.getDropList().size(); i++) {
                ItemTemplate item = ItemTable.getInstance().getTemplate(npc.getDropList().get(i).getItemId());
                String name = item.getName();
                String minMax = npc.getDropList().get(i).getMin() + " - "
                        + (int) Math.floor(npc.getDropList().get(i).getMax() * Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER);

                double chance = npc.getDropList().get(i).getChance() * Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER;

                if (item.isEquipable()) {
                    minMax = npc.getDropList().get(i).getMin() + " - " + npc.getDropList().get(i).getMax();
                }

                if (name.toLowerCase().contains("adena")) {
                    minMax = (int) Math.floor(npc.getDropList().get(i).getMin() * Config.RATE_DROP_AMOUNT_BY_ID.get(57)) + " - "
                            + (int) Math.floor(npc.getDropList().get(i).getMax() * Config.RATE_DROP_AMOUNT_BY_ID.get(57));
                    chance = npc.getDropList().get(i).getChance();
                }

                String chanceS;
                if (chance < 0.00001) {
                    chanceS = "<0.00001%%";
                } else if (chance < 1) {
                    chanceS = decimalFormat0.format(chance) + "%%";
                } else if (chance >= 100) {
                    chanceS = "99.0%%";
                } else {
                    chanceS = decimalFormat.format(chance) + "%%";
                }

                if (!name.toLowerCase().contains("herb")) {
                    s.append(name + "   " + minMax + "   " + chanceS + "\\n");
                }
            }
        }


        if (npc.getDropGroups() != null) {
            for (DropGroupHolder dropG : npc.getDropGroups()) {
                if (dropG.getDropList() != null) {
                    for (int i = 0; i < dropG.getDropList().size(); i++) {
                        ItemTemplate item = ItemTable.getInstance().getTemplate(dropG.getDropList().get(i).getItemId());
                        String name = item.getName();
                        String minMax = dropG.getDropList().get(i).getMin() + " - "
                                + (int) Math.floor(dropG.getDropList().get(i).getMax() * Config.RATE_DEATH_DROP_AMOUNT_MULTIPLIER);

                        double chance = dropG.getDropList().get(i).getChance() * dropG.getChance() / 100 * Config.RATE_DEATH_DROP_CHANCE_MULTIPLIER;

                        if (item.isEquipable()) {
                            minMax = dropG.getDropList().get(i).getMin() + " - " + dropG.getDropList().get(i).getMax();
                        }

                        if (name.toLowerCase().contains("adena")) {
                            minMax = (int) Math.floor(dropG.getDropList().get(i).getMin() * Config.RATE_DROP_AMOUNT_BY_ID.get(57)) + " - "
                                    + (int) Math.floor(dropG.getDropList().get(i).getMax() * Config.RATE_DROP_AMOUNT_BY_ID.get(57));
                            chance = dropG.getDropList().get(i).getChance() * dropG.getChance() / 100;
                        }

                        String chanceS;
                        if (chance < 0.00001) {
                            chanceS = "<0.00001%%";
                        } else if (chance < 1) {
                            chanceS = decimalFormat0.format(chance) + "%%";
                        } else if (chance >= 100) {
                            chanceS = "99.0%%";
                        } else {
                            chanceS = decimalFormat.format(chance) + "%%";
                        }


                        if (!name.toLowerCase().contains("herb")) {
                            s.append(name + "   " + minMax + "   " + chanceS + "\\n");
                        }
                    }
                }
            }
        }

        return skillTxtAtomicPattern.replace("???", s.toString()).replace("###", Integer.toString(index));
    }

}