package npc.model;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ThreadLocalRandom;
import l2.commons.util.Rnd;
import l2.gameserver.ThreadPoolManager;
import l2.gameserver.model.Player;
import l2.gameserver.model.instances.NpcInstance; // Explicit import
import l2.gameserver.network.l2.s2c.NpcHtmlMessage;
import l2.gameserver.scripts.Functions;
import l2.gameserver.templates.npc.NpcTemplate;
import l2.gameserver.utils.NpcUtils;
import l2.gameserver.utils.Location;
public class MonsterWithNPCSpawner extends NpcInstance {
private static final Map<Integer, NPCSpawnData> npcSpawnMap = new HashMap<>();
private static final List<NpcInstance> spawnedNpcs = new ArrayList<>(); // Explicitly typed
private static boolean isConfigLoaded = false;
public MonsterWithNPCSpawner(int objectId, NpcTemplate template) {
super(objectId, template);
System.out.println("[INFO] MonsterWithNPCSpawner script loaded for NPC ID: " + getNpcId());
if (!isConfigLoaded) {
loadConfig();
isConfigLoaded = true;
}
}
private static void loadConfig() {
Properties prop = new Properties();
try (FileInputStream fis = new FileInputStream("config/npc_spawn_config.properties")) {
prop.load(fis);
for (int i = 1; i <= 8; i++) {
String monsterList = prop.getProperty("MonsterID" + i, "");
int npcId = Integer.parseInt(prop.getProperty("NPCID" + i, "0"));
int chance = Integer.parseInt(prop.getProperty("ChanceID" + i, "0"));
String rewardList = prop.getProperty("Rewards" + i, "");
if (!monsterList.isEmpty() && npcId > 0 && chance > 0 && !rewardList.isEmpty()) {
List<Reward> rewards = new ArrayList<>();
for (String rewardEntry : rewardList.split(";")) {
String[] parts = rewardEntry.trim().split(",");
if (parts.length == 2) {
rewards.add(new Reward(Integer.parseInt(parts[0]), Integer.parseInt(parts[1])));
}
}
for (String mobId : monsterList.split(",")) {
npcSpawnMap.put(Integer.parseInt(mobId.trim()), new NPCSpawnData(npcId, chance, rewards));
}
}
}
System.out.println("[DEBUG] npcSpawnMap loaded with " + npcSpawnMap.size() + " entries: " + npcSpawnMap.keySet());
} catch (IOException e) {
System.err.println("Error loading NPC spawn config: " + e.getMessage());
}
}
public void onDeath(Player killer) {
super.onDeath(killer);
System.out.println("[DEBUG] MonsterWithNPCSpawner: NPC " + getNpcId() + " was killed by " + killer.getName());
NPCSpawnData spawnData = npcSpawnMap.get(getNpcId());
if (spawnData != null && Rnd.chance(spawnData.chance)) {
System.out.println("[DEBUG] Spawning NPC for monster ID: " + getNpcId());
spawnNPC(spawnData.npcId, getLoc(), spawnData.rewards);
} else {
System.out.println("[DEBUG] No spawn for NPC ID: " + getNpcId() + " (no data or chance failed)");
}
}
private static void spawnNPC(int npcId, Location loc, List<Reward> rewards) {
try {
NpcInstance npc = NpcUtils.spawnSingle(npcId, loc);
npc.setSpawnedLoc(loc);
spawnedNpcs.add(npc);
if (npc instanceof InteractiveNPC) {
((InteractiveNPC) npc).setRewards(rewards);
}
System.out.println("[INFO] NPC spawned successfully! ID: " + npcId + " at " + loc);
ThreadPoolManager.getInstance().schedule(() -> {
if (npc != null && !npc.isDeleted()) {
System.out.println("[INFO] Despawning NPC ID: " + npcId);
npc.deleteMe();
spawnedNpcs.remove(npc);
}
}, 15000); // 15 seconds
} catch (Exception e) {
System.err.println("[ERROR] Failed to spawn NPC ID: " + npcId + " - " + e.getMessage());
}
}
public static class NPCSpawnData {
public final int npcId;
public final int chance;
public final List<Reward> rewards;
NPCSpawnData(int npcId, int chance, List<Reward> rewards) {
this.npcId = npcId;
this.chance = chance;
this.rewards = rewards;
}
}
public static class Reward {
public final int itemId;
public final int probability;
Reward(int itemId, int probability) {
this.itemId = itemId;
this.probability = probability;
}
}
}
class InteractiveNPC extends NpcInstance {
private List<MonsterWithNPCSpawner.Reward> rewards = new ArrayList<>();
public InteractiveNPC(int objectId, NpcTemplate template) {
super(objectId, template);
}
public void setRewards(List<MonsterWithNPCSpawner.Reward> rewards) {
this.rewards = rewards;
}
@Override
public void onBypassFeedback(Player player, String command) {
if (command.equals("getReward") && !rewards.isEmpty()) {
System.out.println("[DEBUG] Player " + player.getName() + " clicked reward button");
int roll = ThreadLocalRandom.current().nextInt(100);
for (MonsterWithNPCSpawner.Reward reward : rewards) {
if (roll < reward.probability) {
Functions.addItem(player, reward.itemId, 1);
player.sendMessage("You received your reward!");
this.deleteMe();
return;
}
roll -= reward.probability;
}
player.sendMessage("No reward this time!");
this.deleteMe();
}
}
@Override
public void showChatWindow(Player player, int val, Object... replace) {
System.out.println("[DEBUG] Showing chat window to " + player.getName());
NpcHtmlMessage html = new NpcHtmlMessage(player, this);
html.setHtml("<html><body><center><button value=\"Get Reward\" action=\"bypass -h npc_%objectId%_getReward\" width=100 height=20></center></body></html>");
player.sendPacket(html);
}
}