diff --git a/game/data/xml/Custom/VipManager.xml b/game/data/xml/Custom/VipManager.xml new file mode 100644 index 0000000..7d7e373 --- /dev/null +++ b/game/data/xml/Custom/VipManager.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/game/data/xml/items/custom/VipItens.xml b/game/data/xml/items/custom/VipItens.xml new file mode 100644 index 0000000..071021b --- /dev/null +++ b/game/data/xml/items/custom/VipItens.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/TioPatinhas/Vip/VipDAO.java b/java/TioPatinhas/Vip/VipDAO.java new file mode 100644 index 0000000..a7e99e4 --- /dev/null +++ b/java/TioPatinhas/Vip/VipDAO.java @@ -0,0 +1,72 @@ +package TioPatinhas.Vip; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Timestamp; +import java.time.LocalDateTime; + +import net.sf.l2j.L2DatabaseFactory; + +/* + * @author -= TioPatinhas =- + */ +public final class VipDAO +{ + private static final String SELECT = "SELECT tier, expire_at FROM character_vip_player WHERE charId=?"; + private static final String UPSERT = "REPLACE INTO character_vip_player (charId, tier, expire_at) VALUES (?,?,?)"; + private static final String DELETE = "DELETE FROM character_vip_player WHERE charId=?"; + + public static VipStatus load(int charId) + { + try (Connection con = L2DatabaseFactory.getInstance().getConnection(); + PreparedStatement ps = con.prepareStatement(SELECT)) + { + ps.setInt(1, charId); + try (ResultSet rs = ps.executeQuery()) + { + if (rs.next()) + { + final String tier = rs.getString("tier"); + final LocalDateTime exp = rs.getTimestamp("expire_at").toLocalDateTime(); + return new VipStatus(tier, exp); + } + } + } + catch (Exception e) + { + e.printStackTrace(); + } + return null; + } + + public static void save(int charId, String tier, LocalDateTime expireAt) + { + try (Connection con = L2DatabaseFactory.getInstance().getConnection(); + PreparedStatement ps = con.prepareStatement(UPSERT)) + { + ps.setInt(1, charId); + ps.setString(2, tier); + ps.setTimestamp(3, Timestamp.valueOf(expireAt)); + ps.executeUpdate(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public static void delete(int charId) + { + try (Connection con = L2DatabaseFactory.getInstance().getConnection(); + PreparedStatement ps = con.prepareStatement(DELETE)) + { + ps.setInt(1, charId); + ps.executeUpdate(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } +} diff --git a/java/TioPatinhas/Vip/VipData.java b/java/TioPatinhas/Vip/VipData.java new file mode 100644 index 0000000..cf6937c --- /dev/null +++ b/java/TioPatinhas/Vip/VipData.java @@ -0,0 +1,326 @@ +package TioPatinhas.Vip; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/* + * @author -= TioPatinhas =- + */ +public final class VipData +{ + private static final Logger _log = Logger.getLogger(VipData.class.getName()); + private static final VipData INSTANCE = new VipData(); + + public static VipData getInstance() + { + return INSTANCE; + } + + private boolean _enabled = false; + + private final Map> _tierChanceAdd = new HashMap<>(); + private final Map> _tierCountMul = new HashMap<>(); + private final Map _tierTitleColors = new HashMap<>(); + private final Map _tierUseTitleColor = new HashMap<>(); + private final Map _tierXpRate = new HashMap<>(); + private final Map _tierSpRate = new HashMap<>(); + private final Map _tierUseXpSp = new HashMap<>(); + + private final Map _tierEnchantAddGlobal = new HashMap<>(); + private final Map _tierEnchantMulGlobal = new HashMap<>(); + + private final Map> _tierEnchantAddByScroll = new HashMap<>(); + private final Map> _tierEnchantMulByScroll = new HashMap<>(); + + public static final class TokenEntry + { + public final String tier; + public final int days; + + public TokenEntry(String t, int d) + { + tier = t; + days = d; + } + } + + private final Map _tokenByItem = new HashMap<>(); + + private VipData() + { + reload(); + } + + public void reload() + { + _enabled = false; + _tierChanceAdd.clear(); + _tierCountMul.clear(); + _tierTitleColors.clear(); + _tierUseTitleColor.clear(); + _tierXpRate.clear(); + _tierSpRate.clear(); + _tierUseXpSp.clear(); + + _tierEnchantAddGlobal.clear(); + _tierEnchantMulGlobal.clear(); + _tierEnchantAddByScroll.clear(); + _tierEnchantMulByScroll.clear(); + + _tokenByItem.clear(); + + try + { + final File f = new File("./data/xml/Custom/VipManager.xml"); + final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setIgnoringComments(true); + dbf.setExpandEntityReferences(false); + final Document doc = dbf.newDocumentBuilder().parse(f); + doc.getDocumentElement().normalize(); + + final NamedNodeMap rootAttrs = doc.getDocumentElement().getAttributes(); + final Node enabledAttr = rootAttrs.getNamedItem("enabled"); + _enabled = (enabledAttr != null && Boolean.parseBoolean(enabledAttr.getNodeValue())); + + for (Node n = doc.getDocumentElement().getFirstChild(); n != null; n = n.getNextSibling()) + { + if (n.getNodeType() != Node.ELEMENT_NODE) + continue; + + if ("Tier".equalsIgnoreCase(n.getNodeName())) + { + final NamedNodeMap a = n.getAttributes(); + final String name = a.getNamedItem("name").getNodeValue().toLowerCase(); + + // titleColor / useTitleColor + Node tc = a.getNamedItem("titleColor"); + if (tc != null) + _tierTitleColors.put(name, tc.getNodeValue()); + + Node utc = a.getNamedItem("useTitleColor"); + final boolean useTitle = (utc != null && Boolean.parseBoolean(utc.getNodeValue())); + _tierUseTitleColor.put(name, useTitle); + + // xpRate / spRate / useXpSp + double xpRate = 1.0, spRate = 1.0; + Node xr = a.getNamedItem("xpRate"); + Node sr = a.getNamedItem("spRate"); + if (xr != null) + xpRate = Double.parseDouble(xr.getNodeValue()); + if (sr != null) + spRate = Double.parseDouble(sr.getNodeValue()); + _tierXpRate.put(name, xpRate); + _tierSpRate.put(name, spRate); + + Node ux = a.getNamedItem("useXpSp"); + boolean useXpSp = (ux != null && Boolean.parseBoolean(ux.getNodeValue())); + _tierUseXpSp.put(name, useXpSp); + + final Map chanceAdd = new HashMap<>(); + final Map countMul = new HashMap<>(); + + // ENCHANT maps locais do tier + final Map enchAddByScroll = new HashMap<>(); + final Map enchMulByScroll = new HashMap<>(); + Double enchAddGlobal = null; + Double enchMulGlobal = null; + + for (Node c = n.getFirstChild(); c != null; c = c.getNextSibling()) + { + if (c.getNodeType() != Node.ELEMENT_NODE) + continue; + + final String nodeName = c.getNodeName(); + + // Drops + if ("DropBonus".equalsIgnoreCase(nodeName)) + { + final NamedNodeMap ca = c.getAttributes(); + final int itemId = Integer.parseInt(ca.getNamedItem("itemId").getNodeValue()); + + double addPercent = 0.0; + Node ap = ca.getNamedItem("addPercent"); + if (ap != null) + addPercent = Double.parseDouble(ap.getNodeValue()); + if (addPercent != 0.0) + chanceAdd.put(itemId, addPercent); + + double mul = 1.0; + Node cm = ca.getNamedItem("countMul"); + if (cm != null) + mul = Double.parseDouble(cm.getNodeValue()); + if (mul != 1.0) + countMul.put(itemId, mul); + + continue; + } + + // Enchant + if ("EnchantBonus".equalsIgnoreCase(nodeName)) + { + final NamedNodeMap ca = c.getAttributes(); + Node addN = ca.getNamedItem("addPercent"); + Node mulN = ca.getNamedItem("mulRate"); + Node sidN = ca.getNamedItem("scrollId"); + + final Double add = (addN != null) ? Double.parseDouble(addN.getNodeValue()) : null; + final Double mul = (mulN != null) ? Double.parseDouble(mulN.getNodeValue()) : null; + + if (sidN != null) + { + final int scrollId = Integer.parseInt(sidN.getNodeValue()); + if (add != null) + enchAddByScroll.put(scrollId, add); + if (mul != null) + enchMulByScroll.put(scrollId, mul); + } + else + { + if (add != null) + enchAddGlobal = add; + if (mul != null) + enchMulGlobal = mul; + } + } + } + + _tierChanceAdd.put(name, Collections.unmodifiableMap(chanceAdd)); + _tierCountMul.put(name, Collections.unmodifiableMap(countMul)); + + // salva enchant por-tier + _tierEnchantAddByScroll.put(name, Collections.unmodifiableMap(enchAddByScroll)); + _tierEnchantMulByScroll.put(name, Collections.unmodifiableMap(enchMulByScroll)); + if (enchAddGlobal != null) + _tierEnchantAddGlobal.put(name, enchAddGlobal); + if (enchMulGlobal != null) + _tierEnchantMulGlobal.put(name, enchMulGlobal); + + continue; + } + + if ("Token".equalsIgnoreCase(n.getNodeName())) + { + final NamedNodeMap a = n.getAttributes(); + final int itemId = Integer.parseInt(a.getNamedItem("itemId").getNodeValue()); + final String tier = a.getNamedItem("tier").getNodeValue().toLowerCase(); + final int days = Integer.parseInt(a.getNamedItem("days").getNodeValue()); + _tokenByItem.put(itemId, new TokenEntry(tier, days)); + } + } + } + catch (Exception e) + { + e.printStackTrace(); + } + + _log.info("VipData: carregado " + _tierChanceAdd.size() + " tiers, " + _tokenByItem.size() + " tokens."); + } + + public boolean isEnabled() + { + return _enabled; + } + + public double getAddPercent(String tierName, int itemId) + { + if (!_enabled || tierName == null) + return 0.0; + final Map m = _tierChanceAdd.get(tierName.toLowerCase()); + return (m == null) ? 0.0 : m.getOrDefault(itemId, 0.0); + } + + public double getCountMul(String tierName, int itemId) + { + if (!_enabled || tierName == null) + return 1.0; + final Map m = _tierCountMul.get(tierName.toLowerCase()); + return (m == null) ? 1.0 : m.getOrDefault(itemId, 1.0); + } + + public String getTitleColor(String tierName) + { + if (!_enabled || tierName == null) + return null; + return _tierTitleColors.get(tierName.toLowerCase()); + } + + public boolean isUseTitleColor(String tierName) + { + if (!_enabled || tierName == null) + return false; + return _tierUseTitleColor.getOrDefault(tierName.toLowerCase(), false); + } + + public boolean isUseXpSp(String tierName) + { + if (!_enabled || tierName == null) + return false; + return _tierUseXpSp.getOrDefault(tierName.toLowerCase(), false); + } + + public double getXpRate(String tierName) + { + if (!_enabled || tierName == null) + return 1.0; + return _tierXpRate.getOrDefault(tierName.toLowerCase(), 1.0); + } + + public double getSpRate(String tierName) + { + if (!_enabled || tierName == null) + return 1.0; + return _tierSpRate.getOrDefault(tierName.toLowerCase(), 1.0); + } + + public double getEnchantAddPercent(String tierName, int scrollId) + { + if (!_enabled || tierName == null) + return 0.0; + final String t = tierName.toLowerCase(); + final Map byScroll = _tierEnchantAddByScroll.get(t); + if (byScroll != null) + { + final Double v = byScroll.get(scrollId); + if (v != null) + return v; + } + return _tierEnchantAddGlobal.getOrDefault(t, 0.0); + } + + public double getEnchantMulRate(String tierName, int scrollId) + { + if (!_enabled || tierName == null) + return 1.0; + final String t = tierName.toLowerCase(); + final Map byScroll = _tierEnchantMulByScroll.get(t); + if (byScroll != null) + { + final Double v = byScroll.get(scrollId); + if (v != null) + return v; + } + return _tierEnchantMulGlobal.getOrDefault(t, 1.0); + } + + public static int parseColor(String hex) + { + if (hex == null) + return 0xFFFFFF; + String clean = hex.replace("#", ""); + return (int) Long.parseLong(clean, 16); + } + + public TokenEntry getToken(int itemId) + { + return _tokenByItem.get(itemId); + } +} diff --git a/java/TioPatinhas/Vip/VipManager.java b/java/TioPatinhas/Vip/VipManager.java new file mode 100644 index 0000000..19ac606 --- /dev/null +++ b/java/TioPatinhas/Vip/VipManager.java @@ -0,0 +1,205 @@ +package TioPatinhas.Vip; + +import java.time.Duration; +import java.time.LocalDateTime; + +import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance; +import net.sf.l2j.gameserver.network.clientpackets.Say2; +import net.sf.l2j.gameserver.network.serverpackets.CreatureSay; + +/* + * @author -= TioPatinhas =- + */ +public final class VipManager +{ + private static final VipManager INSTANCE = new VipManager(); + + public static VipManager getInstance() + { + return INSTANCE; + } + + private VipManager() + { + } + + public void onLogin(L2PcInstance player) + { + final VipStatus stage = VipDAO.load(player.getObjectId()); + if (stage != null && stage.isActive()) + { + player.setNewVipTier(stage.tier); + player.setNewVipExpire(stage.expire); + applyTitleColorFromTier(player, stage.tier); + + final String left = formatRemaining(LocalDateTime.now(), stage.expire); + player.sendPacket(new CreatureSay(0, Say2.CRITICAL_ANNOUNCE, "", "Seu VIP " + stage.tier + " expira em " + left + ".")); + warnIfLessThanOneDay(player, stage.expire); + } + else + { + player.setNewVipTier(null); + player.setNewVipExpire(null); + if (stage != null) + VipDAO.delete(player.getObjectId()); + resetTitleColorToDefault(player); + } + } + + public void setVip(L2PcInstance player, String tier, int days) + { + LocalDateTime base = LocalDateTime.now(); + if (player.getNewVipExpire() != null && base.isBefore(player.getNewVipExpire())) + base = player.getNewVipExpire(); + + final LocalDateTime exp = base.plusDays(Math.max(1, days)); + final String normTier = tier.toLowerCase(); + + VipDAO.save(player.getObjectId(), normTier, exp); + player.setNewVipTier(normTier); + player.setNewVipExpire(exp); + + applyTitleColorFromTier(player, normTier); + + final String left = formatRemaining(LocalDateTime.now(), exp); + player.sendMessage("VIP " + normTier + " renovado. Expira em " + left + "."); + player.sendPacket(new CreatureSay(0, Say2.CRITICAL_ANNOUNCE, "", "VIP " + normTier + " renovado. Expira em " + left + ".")); + warnIfLessThanOneDay(player, exp); + } + + public void clearVip(L2PcInstance player) + { + VipDAO.delete(player.getObjectId()); + player.setNewVipTier(null); + player.setNewVipExpire(null); + resetTitleColorToDefault(player); + player.sendMessage("Seu VIP foi removido."); + player.sendPacket(new CreatureSay(0, Say2.CRITICAL_ANNOUNCE, "", "Seu VIP foi removido.")); + } + + public double getDropAddPercent(L2PcInstance player, int itemId) + { + if (player == null || player.getNewVipTier() == null) + return 0.0; + return VipData.getInstance().getAddPercent(player.getNewVipTier(), itemId); + } + + public double getCountMultiplier(L2PcInstance player, int itemId) + { + if (player == null || player.getNewVipTier() == null) + return 1.0; + return VipData.getInstance().getCountMul(player.getNewVipTier(), itemId); + } + + // XP / SP + public double getXpRateMultiplier(L2PcInstance player) + { + if (player == null) + return 1.0; + final String tier = player.getNewVipTier(); + if (tier == null) + return 1.0; + if (!VipData.getInstance().isUseXpSp(tier)) + return 1.0; + return VipData.getInstance().getXpRate(tier); + } + + public double getSpRateMultiplier(L2PcInstance player) + { + if (player == null) + return 1.0; + final String tier = player.getNewVipTier(); + if (tier == null) + return 1.0; + if (!VipData.getInstance().isUseXpSp(tier)) + return 1.0; + return VipData.getInstance().getSpRate(tier); + } + + public double getEnchantAddPercent(L2PcInstance player, int scrollId) + { + if (player == null) + return 0.0; + final String tier = player.getNewVipTier(); + if (tier == null) + return 0.0; + return VipData.getInstance().getEnchantAddPercent(tier, scrollId); + } + + public double getEnchantMulRate(L2PcInstance player, int scrollId) + { + if (player == null) + return 1.0; + final String tier = player.getNewVipTier(); + if (tier == null) + return 1.0; + return VipData.getInstance().getEnchantMulRate(tier, scrollId); + } + + private void applyTitleColorFromTier(L2PcInstance player, String tier) + { + if (player == null || tier == null) + return; + if (!VipData.getInstance().isUseTitleColor(tier)) + return; + + final String hex = VipData.getInstance().getTitleColor(tier); + if (hex == null) + return; + + try + { + final int rgb = VipData.parseColor(hex); // "#rrggbb" -> 0xRRGGBB + player.getAppearance().setTitleColor(rgb); + player.broadcastUserInfo(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + private void resetTitleColorToDefault(L2PcInstance player) + { + if (player == null) + return; + + final int DEFAULT_TITLE_COLOR = 0xFFFF77; + try + { + player.getAppearance().setTitleColor(DEFAULT_TITLE_COLOR); + player.broadcastUserInfo(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + private static String formatRemaining(LocalDateTime now, LocalDateTime expire) + { + if (expire == null || !expire.isAfter(now)) + return "0d 00h 00m"; + + Duration day = Duration.between(now, expire); + long totalMin = day.toMinutes(); + long days = totalMin / (24 * 60); + long hours = (totalMin % (24 * 60)) / 60; + long mins = totalMin % 60; + return String.format("%ddias %02dhoras %02dminutos", days, hours, mins); + } + + private static void warnIfLessThanOneDay(L2PcInstance player, LocalDateTime expire) + { + if (expire == null) + return; + + Duration days = Duration.between(LocalDateTime.now(), expire); + if (!days.isNegative() && days.compareTo(Duration.ofHours(24)) <= 0) + { + long hours = Math.max(0, days.toHours()); + player.sendMessage("Aviso: seu VIP expira em menos de 24h (" + hours + "h)."); + player.sendPacket(new CreatureSay(0, Say2.CRITICAL_ANNOUNCE, "Aviso: ", "seu VIP expira em menos de 24h (" + hours + "h).")); + } + } +} diff --git a/java/TioPatinhas/Vip/VipStatus.java b/java/TioPatinhas/Vip/VipStatus.java new file mode 100644 index 0000000..53dfd7a --- /dev/null +++ b/java/TioPatinhas/Vip/VipStatus.java @@ -0,0 +1,23 @@ +package TioPatinhas.Vip; + +import java.time.LocalDateTime; + +/* + * @author -= TioPatinhas =- + */ +public final class VipStatus +{ + public final String tier; + public final LocalDateTime expire; + + public VipStatus(String tier, LocalDateTime expire) + { + this.tier = tier; + this.expire = expire; + } + + public boolean isActive() + { + return tier != null && expire != null && LocalDateTime.now().isBefore(expire); + } +} diff --git a/java/net/sf/l2j/gameserver/GameServer.java b/java/net/sf/l2j/gameserver/GameServer.java index 88af6d2..41024a0 100644 --- a/java/net/sf/l2j/gameserver/GameServer.java +++ b/java/net/sf/l2j/gameserver/GameServer.java @@ -211,6 +211,7 @@ import TioPatinhas.Dungeon.DungeonManager; import TioPatinhas.Fusion.data.ItemFusionData; import TioPatinhas.TerritoryWar.TerritoryWarInit; +import TioPatinhas.Vip.VipData; import TioPatinhas.WhatsApp.WhatsappBridge; import hwid.Hwid; import phantom.FakePlayerConfig; @@ -576,6 +577,7 @@ _log.info("Battle Farm Event is disabled"); ItemFusionData.getInstance(); + VipData.getInstance(); Util.printSection("Lotus Dev: Interface"); TeleportLocationDataLotus.getInstance(); diff --git a/java/net/sf/l2j/gameserver/handler/AdminCommandHandler.java b/java/net/sf/l2j/gameserver/handler/AdminCommandHandler.java index 646ec73..4fc3ad5 100644 --- a/java/net/sf/l2j/gameserver/handler/AdminCommandHandler.java +++ b/java/net/sf/l2j/gameserver/handler/AdminCommandHandler.java @@ -66,6 +66,7 @@ import net.sf.l2j.gameserver.handler.admincommandhandlers.AdminMonsterRace; import net.sf.l2j.gameserver.handler.admincommandhandlers.AdminMovieMaker; import net.sf.l2j.gameserver.handler.admincommandhandlers.AdminMultiTvT; +import net.sf.l2j.gameserver.handler.admincommandhandlers.AdminNewVip; import net.sf.l2j.gameserver.handler.admincommandhandlers.AdminOlympiad; import net.sf.l2j.gameserver.handler.admincommandhandlers.AdminPCBPoint; import net.sf.l2j.gameserver.handler.admincommandhandlers.AdminPForge; @@ -184,6 +185,7 @@ registerAdminCommandHandler(new AdminSearch()); registerAdminCommandHandler(new AdminScanPlayers()); registerAdminCommandHandler(new AdminWhatsapp()); + registerAdminCommandHandler(new AdminNewVip()); } public void registerAdminCommandHandler(IAdminCommandHandler handler) diff --git a/java/net/sf/l2j/gameserver/handler/ItemHandler.java b/java/net/sf/l2j/gameserver/handler/ItemHandler.java index 7ecd306..edef874 100644 --- a/java/net/sf/l2j/gameserver/handler/ItemHandler.java +++ b/java/net/sf/l2j/gameserver/handler/ItemHandler.java @@ -50,6 +50,7 @@ import net.sf.l2j.gameserver.handler.itemhandlers.SpecialXMas; import net.sf.l2j.gameserver.handler.itemhandlers.SpiritShot; import net.sf.l2j.gameserver.handler.itemhandlers.SummonItems; +import net.sf.l2j.gameserver.handler.itemhandlers.VipToken; import net.sf.l2j.gameserver.handler.itemhandlers.clan.ClanLevel; import net.sf.l2j.gameserver.handler.itemhandlers.clan.ClanReputation; import net.sf.l2j.gameserver.handler.itemhandlers.clan.skills.SkillAegis; @@ -144,6 +145,7 @@ registerItemHandler(new RouletteItem()); registerItemHandler(new AgationItems()); registerItemHandler(new CapsuleBox()); + registerItemHandler(new VipToken()); if (Config.ALLOW_ITEM_RECOVER) diff --git a/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminNewVip.java b/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminNewVip.java new file mode 100644 index 0000000..dca9a8c --- /dev/null +++ b/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminNewVip.java @@ -0,0 +1,93 @@ +package net.sf.l2j.gameserver.handler.admincommandhandlers; + +import java.util.StringTokenizer; + +import net.sf.l2j.gameserver.handler.IAdminCommandHandler; +import net.sf.l2j.gameserver.model.L2World; +import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance; + +import TioPatinhas.Vip.VipData; +import TioPatinhas.Vip.VipManager; + +/* + * @author -= TioPatinhas =- + */ +public class AdminNewVip implements IAdminCommandHandler +{ + + private static final String[] ADMIN_COMMANDS = + { + "admin_newvip", + "admin_clearvip", + "admin_reloadvip" + }; + + private L2PcInstance resolvePlayer(L2PcInstance admin, String nameOrDot) + { + if (nameOrDot.equals(".") && admin.getTarget() instanceof L2PcInstance) + return (L2PcInstance) admin.getTarget(); + return L2World.getInstance().getPlayer(nameOrDot); + } + + @Override + public boolean useAdminCommand(String command, L2PcInstance activeChar) + { + final StringTokenizer st = new StringTokenizer(command, " "); + final String cmd = st.nextToken(); + + if ("admin_newvip".equalsIgnoreCase(cmd)) + { + if (st.countTokens() < 3) + { + activeChar.sendMessage("Uso: //newvip "); + return true; + } + final String playerName = st.nextToken(); + final String tier = st.nextToken().toLowerCase(); + final int days = Integer.parseInt(st.nextToken()); + + final L2PcInstance target = resolvePlayer(activeChar, playerName); + if (target == null) + { + activeChar.sendMessage("Player offline."); + return true; + } + + VipManager.getInstance().setVip(target, tier, days); + activeChar.sendMessage("VIP setado: " + target.getName() + " -> " + tier + " (" + days + "Dia(s))"); + target.sendMessage("Seu VIP foi ativado: " + tier + " por " + days + " dia(s)."); + return true; + } + else if ("admin_clearvip".equalsIgnoreCase(cmd)) + { + if (!st.hasMoreTokens()) + { + activeChar.sendMessage("Uso: //clearvip "); + return true; + } + final L2PcInstance target = resolvePlayer(activeChar, st.nextToken()); + if (target == null) + { + activeChar.sendMessage("Player offline."); + return true; + } + VipManager.getInstance().clearVip(target); + activeChar.sendMessage("VIP removido de " + target.getName()); + target.sendMessage("Seu VIP foi removido."); + return true; + } + else if ("admin_reloadvip".equalsIgnoreCase(cmd)) + { + VipData.getInstance().reload(); + activeChar.sendMessage("O VipData e VipItems Foram recarregado."); + return true; + } + return false; + } + + @Override + public String[] getAdminCommandList() + { + return ADMIN_COMMANDS; + } +} diff --git a/java/net/sf/l2j/gameserver/handler/itemhandlers/VipToken.java b/java/net/sf/l2j/gameserver/handler/itemhandlers/VipToken.java new file mode 100644 index 0000000..b962cad --- /dev/null +++ b/java/net/sf/l2j/gameserver/handler/itemhandlers/VipToken.java @@ -0,0 +1,48 @@ +package net.sf.l2j.gameserver.handler.itemhandlers; + +import net.sf.l2j.gameserver.handler.IItemHandler; +import net.sf.l2j.gameserver.model.actor.L2Playable; +import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance; +import net.sf.l2j.gameserver.model.item.instance.ItemInstance; +import net.sf.l2j.gameserver.network.SystemMessageId; +import net.sf.l2j.gameserver.network.clientpackets.Say2; +import net.sf.l2j.gameserver.network.serverpackets.CreatureSay; +import net.sf.l2j.gameserver.network.serverpackets.SystemMessage; + +import TioPatinhas.Vip.VipData; +import TioPatinhas.Vip.VipManager; + +/* + * @author -= TioPatinhas =- + */ +public final class VipToken implements IItemHandler +{ + + @Override + public void useItem(L2Playable playable, ItemInstance item, boolean forceUse) + { + if (!(playable instanceof L2PcInstance)) + return; + + final L2PcInstance player = (L2PcInstance) playable; + + final VipData.TokenEntry token = VipData.getInstance().getToken(item.getItemId()); + if (token == null) + { + player.sendMessage("Token VIP inválido ou não configurado no VipManager.xml."); + return; + } + + if (!player.destroyItemByItemId("VipToken", item.getItemId(), 1, player, true)) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.NOT_ENOUGH_ITEMS)); + return; + } + + final int days = Math.max(1, token.days); + VipManager.getInstance().setVip(player, token.tier, days); + + player.sendMessage("VIP " + token.tier + " aplicado/renovado por " + days + " dia(s)."); + player.sendPacket(new CreatureSay(0, Say2.CRITICAL_ANNOUNCE, "", "VIP " + token.tier + " aplicado/renovado por " + days + " dia(s).")); + } +} diff --git a/java/net/sf/l2j/gameserver/model/actor/L2Attackable.java b/java/net/sf/l2j/gameserver/model/actor/L2Attackable.java index 02fc312..ff3a8a9 100644 --- a/java/net/sf/l2j/gameserver/model/actor/L2Attackable.java +++ b/java/net/sf/l2j/gameserver/model/actor/L2Attackable.java @@ -76,6 +76,8 @@ import TioPatinhas.BattleFarm.event.AbstractBattleFarm; import TioPatinhas.BattleFarm.event.RewardMobRegistry; import TioPatinhas.BossEngine.CustomBossManager; +import TioPatinhas.Vip.VipData; +import TioPatinhas.Vip.VipManager; /** * This class manages all NPC that can be attacked, such as : @@ -643,6 +645,16 @@ sp *= Config.VIP_XP_SP_RATE; } + if (attacker != null && attacker.isNewVip() && VipData.getInstance().isUseXpSp(attacker.getNewVipTier())) + { + final double xpMul = VipManager.getInstance().getXpRateMultiplier(attacker); + final double spMul = VipManager.getInstance().getSpRateMultiplier(attacker); + + exp = Math.round(exp * xpMul); + sp = (int) Math.round(sp * spMul); + } + exp *= 1 - penalty; if (isOverhit() && _overhitAttacker != null && _overhitAttacker.getActingPlayer() != null && attacker == _overhitAttacker.getActingPlayer()) @@ -734,6 +746,17 @@ exp *= Config.VIP_XP_SP_RATE; sp *= Config.VIP_XP_SP_RATE; } + + if (attacker != null && attacker.isNewVip() && VipData.getInstance().isUseXpSp(attacker.getNewVipTier())) + { + final double xpMul = VipManager.getInstance().getXpRateMultiplier(attacker); + final double spMul = VipManager.getInstance().getSpRateMultiplier(attacker); + + exp = Math.round(exp * xpMul); + sp = (int) Math.round(sp * spMul); + } + } if (isChampion()) @@ -751,6 +774,15 @@ exp *= Config.VIP_XP_SP_RATE; sp *= Config.VIP_XP_SP_RATE; } + if (attacker != null && attacker.isNewVip() && VipData.getInstance().isUseXpSp(attacker.getNewVipTier())) + { + final double xpMul = VipManager.getInstance().getXpRateMultiplier(attacker); + final double spMul = VipManager.getInstance().getSpRateMultiplier(attacker); + + exp = Math.round(exp * xpMul); + sp = (int) Math.round(sp * spMul); + } } exp *= partyMul; @@ -1069,6 +1101,18 @@ if (isChampion()) dropChance *= Config.CHAMPION_REWARDS; + if (lastAttacker != null && VipData.getInstance().isEnabled() && lastAttacker.isNewVip()) + { + final double addPercent = VipManager.getInstance().getDropAddPercent(lastAttacker, drop.getItemId()); + + if (addPercent > 0.0) + { + final double addInChanceUnits = addPercent * (DropData.MAX_CHANCE / 100.0); // MAX_CHANCE = 100% + dropChance += addInChanceUnits; + } + } + // Set our limits for chance of drop if (dropChance < 1) dropChance = 1; @@ -1104,6 +1148,27 @@ if (drop.getItemId() >= 6360 && drop.getItemId() <= 6362) itemCount *= Config.RATE_DROP_SEAL_STONES; + if (itemCount > 0 && lastAttacker != null && VipData.getInstance().isEnabled() && lastAttacker.isNewVip()) + { + final double mul = VipManager.getInstance().getCountMultiplier(lastAttacker, drop.getItemId()); + + if (mul > 1.0) + { + final int base = itemCount; + final int whole = (int) Math.floor(mul); + final double frac = mul - whole; + + long newCount = (long) base * (long) whole; + if (frac > 0d && Rnd.nextDouble() < frac) + newCount += base; + + if (newCount < 1 && itemCount > 0) + newCount = 1; + itemCount = (int) Math.min(Integer.MAX_VALUE, newCount); + } + } + if (lastAttacker.isVip()) { if (drop.getItemId() == Config.VIP_DROP_RATE) @@ -1187,6 +1252,14 @@ if (isChampion()) dropChance *= Config.CHAMPION_REWARDS; + if (lastAttacker != null && VipData.getInstance().isEnabled() && lastAttacker.isNewVip()) + { + final double addPercent = VipManager.getInstance().getDropAddPercent(lastAttacker, drop.getItemId()); + if (addPercent > 0.0) + dropChance += (addPercent * (DropData.MAX_CHANCE / 100.0)); + } + if (dropChance < DropData.MAX_CHANCE) dropChance = DropData.MAX_CHANCE; @@ -1232,6 +1305,26 @@ } } + if (itemCount > 0 && lastAttacker != null && VipData.getInstance().isEnabled() && lastAttacker.isNewVip()) + { + final double mul = VipManager.getInstance().getCountMultiplier(lastAttacker, drop.getItemId()); + if (mul > 1.0) + { + final int base = itemCount; + final int whole = (int) Math.floor(mul); + final double frac = mul - whole; + + long newCount = (long) base * (long) whole; + if (frac > 0d && Rnd.nextDouble() < frac) + newCount += base; + + if (newCount < 1 && itemCount > 0) + newCount = 1; + itemCount = (int) Math.min(Integer.MAX_VALUE, newCount); + } + } + if (itemCount > 0) return new ItemHolder(drop.getItemId(), itemCount, drop.getMinEnchant(), drop.getMaxEnchant(), drop.getEnchantSucess()); } diff --git a/java/net/sf/l2j/gameserver/model/actor/instance/L2PcInstance.java b/java/net/sf/l2j/gameserver/model/actor/instance/L2PcInstance.java index ae7ddc0..cf38913 100644 --- a/java/net/sf/l2j/gameserver/model/actor/instance/L2PcInstance.java +++ b/java/net/sf/l2j/gameserver/model/actor/instance/L2PcInstance.java @@ -17,6 +17,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -14613,4 +14614,34 @@ { _originalBatlleTitleColor = color; } + + // NewVIP + private String _vipTier = null; + private LocalDateTime _vipExpire = null; + + public void setNewVipTier(String t) + { + _vipTier = t; + } + + public String getNewVipTier() + { + return _vipTier; + } + + public void setNewVipExpire(LocalDateTime e) + { + _vipExpire = e; + } + + public LocalDateTime getNewVipExpire() + { + return _vipExpire; + } + + public boolean isNewVip() + { + return _vipTier != null && _vipExpire != null && LocalDateTime.now().isBefore(_vipExpire); + } + } \ No newline at end of file diff --git a/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java b/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java index 2ce2d4a..07635f1 100644 --- a/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java +++ b/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java @@ -106,6 +106,7 @@ import TioPatinhas.BotPrevention.BotsPreventionManager; import TioPatinhas.DollSystem.DollsData; +import TioPatinhas.Vip.VipManager; import hwid.Hwid; import phantom.FakePlayer; @@ -487,6 +488,8 @@ L2ClassMasterInstance.showQuestionMark(activeChar); + VipManager.getInstance().onLogin(activeChar); + // VIP Delete if (activeChar.isVip()) { diff --git a/java/net/sf/l2j/gameserver/network/clientpackets/RequestEnchantItem.java b/java/net/sf/l2j/gameserver/network/clientpackets/RequestEnchantItem.java index a1c9d5c..2e836f8 100644 --- a/java/net/sf/l2j/gameserver/network/clientpackets/RequestEnchantItem.java +++ b/java/net/sf/l2j/gameserver/network/clientpackets/RequestEnchantItem.java @@ -29,6 +29,8 @@ import net.sf.l2j.gameserver.util.Broadcast; import net.sf.l2j.util.Rnd; +import TioPatinhas.Vip.VipManager; + public final class RequestEnchantItem extends L2GameClientPacket { private int _objectId; @@ -104,6 +106,28 @@ synchronized (item) { + + double chance = enchant.getChance(item); + + // if (player != null && player.isNewVip()) + if (player.isNewVip()) + { + final int scrollId = scroll.getItemId(); + final double mul = VipManager.getInstance().getEnchantMulRate(player, scrollId); + final double add = VipManager.getInstance().getEnchantAddPercent(player, scrollId); + + if (mul != 1.0) + chance *= mul; + if (add != 0.0) + chance += add; + + if (chance < 0.0) + chance = 0.0; + if (chance > 100.0) + chance = 100.0; + } + if (Rnd.get(100) < enchant.getChance(item)) // success { // announce the success //================================== SQL =========== SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for character_vip_player -- ---------------------------- DROP TABLE IF EXISTS `character_vip_player`; CREATE TABLE `character_vip_player` ( `charId` int(11) NOT NULL, `tier` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `expire_at` datetime NOT NULL, `updated_at` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`charId`) USING BTREE, INDEX `idx_character_vip_expire`(`expire_at` ASC) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of character_vip_player -- ---------------------------- SET FOREIGN_KEY_CHECKS = 1;