diff --git a/game-server/config/administration/commands.properties b/game-server/config/administration/commands.properties index 731533604..8efcdf794 100644 --- a/game-server/config/administration/commands.properties +++ b/game-server/config/administration/commands.properties @@ -114,6 +114,7 @@ zone = 9 # Player Commands: # (depends on membership) # ---------------------------- +advent = 0 buy = 0 decompose = 0 del = 0 diff --git a/game-server/data/handlers/playercommands/Advent.java b/game-server/data/handlers/playercommands/Advent.java new file mode 100644 index 000000000..b2f82b2e7 --- /dev/null +++ b/game-server/data/handlers/playercommands/Advent.java @@ -0,0 +1,31 @@ +package playercommands; + +import java.awt.*; + +import com.aionemu.gameserver.model.gameobjects.player.Player; +import com.aionemu.gameserver.services.reward.AdventService; +import com.aionemu.gameserver.utils.ChatUtil; +import com.aionemu.gameserver.utils.chathandlers.PlayerCommand; + +/** + * @author Neon + */ +public class Advent extends PlayerCommand { + + public Advent() { + super("advent", "Gets your advent reward for today."); + + setSyntaxInfo(" - Shows today's reward.", " - Gets your reward for today on this character.\n" + ChatUtil.color("ATTENTION!", Color.RED) + + " Only one character per account can receive this reward!"); + } + + @Override + public void execute(Player player, String... params) { + if (params.length != 1) + sendInfo(player); + else if ("show".equalsIgnoreCase(params[0])) + AdventService.getInstance().showTodaysReward(player); + else if ("get".equalsIgnoreCase(params[0])) + AdventService.getInstance().redeemReward(player); + } +} diff --git a/game-server/sql/update.sql b/game-server/sql/update.sql index 78ef84c46..6c816b63b 100644 --- a/game-server/sql/update.sql +++ b/game-server/sql/update.sql @@ -2,4 +2,14 @@ * DB changes since 9556a4b (30.11.2024) */ -ALTER TABLE `legion_history` DROP COLUMN `tab_id`; \ No newline at end of file +ALTER TABLE `legion_history` DROP COLUMN `tab_id`; + +-- drop advent calendar table +drop table advent; + +-- create advent calendar table +CREATE TABLE `advent` ( + `account_id` int(11) NOT NULL, + `last_day_received` tinyint(4) NOT NULL, + PRIMARY KEY (`account_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/game-server/src/com/aionemu/gameserver/dao/AdventDAO.java b/game-server/src/com/aionemu/gameserver/dao/AdventDAO.java new file mode 100644 index 000000000..411975754 --- /dev/null +++ b/game-server/src/com/aionemu/gameserver/dao/AdventDAO.java @@ -0,0 +1,39 @@ +package com.aionemu.gameserver.dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.aionemu.commons.database.DatabaseFactory; +import com.aionemu.gameserver.model.gameobjects.player.Player; + +/** + * @author Neon + */ +public class AdventDAO { + + public static int getLastReceivedDay(Player player) { + try (Connection con = DatabaseFactory.getConnection(); + PreparedStatement stmt = con.prepareStatement("SELECT `last_day_received` FROM `advent` WHERE ? = account_id")) { + stmt.setInt(1, player.getAccount().getId()); + try (ResultSet rs = stmt.executeQuery()) { + rs.next(); + return rs.getInt("last_day_received"); + } + } catch (SQLException e) { + return 0; + } + } + + public static boolean storeLastReceivedDay(Player player, int dayOfMonth) { + try (Connection con = DatabaseFactory.getConnection(); PreparedStatement stmt = con.prepareStatement("REPLACE INTO `advent` VALUES (?, ?)")) { + stmt.setInt(1, player.getAccount().getId()); + stmt.setInt(2, dayOfMonth); + stmt.execute(); + return true; + } catch (SQLException e) { + return false; + } + } +} diff --git a/game-server/src/com/aionemu/gameserver/services/player/PlayerEnterWorldService.java b/game-server/src/com/aionemu/gameserver/services/player/PlayerEnterWorldService.java index 8eef67221..3cd4c026d 100644 --- a/game-server/src/com/aionemu/gameserver/services/player/PlayerEnterWorldService.java +++ b/game-server/src/com/aionemu/gameserver/services/player/PlayerEnterWorldService.java @@ -58,7 +58,7 @@ import com.aionemu.gameserver.services.instance.InstanceService; import com.aionemu.gameserver.services.mail.MailService; import com.aionemu.gameserver.services.panesterra.PanesterraService; -import com.aionemu.gameserver.services.panesterra.ahserion.AhserionRaid; +import com.aionemu.gameserver.services.reward.AdventService; import com.aionemu.gameserver.services.reward.VeteranRewardService; import com.aionemu.gameserver.services.teleport.BindPointTeleportService; import com.aionemu.gameserver.services.teleport.TeleportService; @@ -323,6 +323,8 @@ private static void enterWorld(AionConnection client, Player player) { if (HTMLConfig.ENABLE_HTML_WELCOME) HTMLService.showHTML(player, HTMLCache.getInstance().getHTML("welcome.xhtml")); + AdventService.getInstance().onLogin(player); + player.getNpcFactions().sendDailyQuest(); if (HTMLConfig.ENABLE_GUIDES) diff --git a/game-server/src/com/aionemu/gameserver/services/reward/AdventService.java b/game-server/src/com/aionemu/gameserver/services/reward/AdventService.java new file mode 100644 index 000000000..e2b391864 --- /dev/null +++ b/game-server/src/com/aionemu/gameserver/services/reward/AdventService.java @@ -0,0 +1,203 @@ +package com.aionemu.gameserver.services.reward; + +import java.awt.*; +import java.time.Month; +import java.time.ZonedDateTime; +import java.util.*; +import java.util.List; + +import com.aionemu.gameserver.dao.AdventDAO; +import com.aionemu.gameserver.dataholders.DataManager; +import com.aionemu.gameserver.model.gameobjects.LetterType; +import com.aionemu.gameserver.model.gameobjects.player.Player; +import com.aionemu.gameserver.model.templates.item.ItemTemplate; +import com.aionemu.gameserver.model.templates.survey.CustomSurveyItem; +import com.aionemu.gameserver.services.mail.SystemMailService; +import com.aionemu.gameserver.utils.ChatUtil; +import com.aionemu.gameserver.utils.PacketSendUtility; +import com.aionemu.gameserver.utils.time.ServerTime; + +/** + * @author Nathan, Estrayl, Neon, Sykra + */ +public class AdventService { + + private static final AdventService instance = new AdventService(); + private final Map> rewards = new HashMap<>(); + + private AdventService() { + for (int i = 1; i <= 25; i++) + rewards.put(i, new ArrayList<>()); + initMaps(); + } + + private void initMaps() { + // Solorius Glasses + rewards.get(1).add(new CustomSurveyItem(125045107, 1)); + // [Event] Solorius Cookie + rewards.get(2).add(new CustomSurveyItem(160010201, 25)); + // Gathering Boost Charm II - 100% + rewards.get(3).add(new CustomSurveyItem(169620082, 1)); + // [Event] 12 Solorius Polar Bear Form Candy (ELYOS) + rewards.get(4).add(new CustomSurveyItem(188051293, 1)); + // [Event] 12 Solorius Polar Bear Form Candy (ASMODIANS) + rewards.get(4).add(new CustomSurveyItem(188051294, 1)); + // Tempering Solution + rewards.get(5).add(new CustomSurveyItem(166030005, 5)); + // [Solorius] Display Furniture Pack + rewards.get(6).add(new CustomSurveyItem(188051875, 1)); + // [Event] Drana Coffee + rewards.get(7).add(new CustomSurveyItem(164002167, 25)); + // Amplification Stone + rewards.get(8).add(new CustomSurveyItem(166500002, 5)); + // AP Boost Charm II - 30% + rewards.get(9).add(new CustomSurveyItem(169620072, 2)); + // [Event] Solorius Coin + rewards.get(10).add(new CustomSurveyItem(186000177, 15)); + // Blood Mark Box + rewards.get(11).add(new CustomSurveyItem(188053636, 2)); + // Omega Enchantment Stone + rewards.get(12).add(new CustomSurveyItem(166020000, 10)); + // Dashing Solorius Costume + rewards.get(13).add(new CustomSurveyItem(110900933, 1)); + // Dashing Solorius Hat + rewards.get(13).add(new CustomSurveyItem(125045555, 1)); + // Ceramium Medal + rewards.get(14).add(new CustomSurveyItem(186000242, 5)); + // [Event] Level 60 Composite Manastone Bundle + rewards.get(15).add(new CustomSurveyItem(188053609, 5)); + // Ahserion's Flight Ancient Manastone Bundle + rewards.get(16).add(new CustomSurveyItem(188053113, 3)); + // [Solorius] Display Furniture Pack + rewards.get(17).add(new CustomSurveyItem(188051875, 1)); + // Honorable Elim's Idian Bundle + rewards.get(18).add(new CustomSurveyItem(188053618, 1)); + // Sublime Life Serum + rewards.get(19).add(new CustomSurveyItem(162000137, 15)); + // Sublime Mana Serum + rewards.get(19).add(new CustomSurveyItem(162000139, 15)); + // Sublime Wind Serum + rewards.get(19).add(new CustomSurveyItem(162000141, 15)); + // Crafting Boost Charm III - 100% + rewards.get(20).add(new CustomSurveyItem(169620094, 1)); + // Special Courier Pass (Mythic/Lv. 61-65) + rewards.get(21).add(new CustomSurveyItem(188950019, 2)); + // Major Danuar Relic + rewards.get(22).add(new CustomSurveyItem(186000247, 5)); + // [Event] Level 70 Composite Manastone Bundle + rewards.get(23).add(new CustomSurveyItem(188053610, 3)); + // Ahserion's Equipment Box + rewards.get(24).add(new CustomSurveyItem(188053109, 1)); + // Assured Greater Felicitous Socketing (Eternal) + rewards.get(24).add(new CustomSurveyItem(166150018, 5)); + } + + public void onLogin(Player player) { + ZonedDateTime now = ServerTime.now(); + int day = now.getDayOfMonth(); + if (now.getMonth() != Month.DECEMBER) + return; + if (!rewards.containsKey(day) || rewards.get(day).isEmpty()) + return; + if (AdventDAO.getLastReceivedDay(player) < day) + PacketSendUtility.sendMessage(player, + "You can open your advent calendar door for today!" + "\nType in .advent to redeem todays reward on this character.\n" + + ChatUtil.color("ATTENTION:", Color.ORANGE) + " Only one character per account can receive this reward!"); + } + + public void redeemReward(Player player) { + ZonedDateTime now = ServerTime.now(); + int day = now.getDayOfMonth(); + List todaysRewards = rewards.get(day); + + if (now.getMonth() != Month.DECEMBER || todaysRewards == null || todaysRewards.isEmpty()) { + PacketSendUtility.sendMessage(player, "There is no advent calendar door for today."); + return; + } + + if (AdventDAO.getLastReceivedDay(player) >= day) { + PacketSendUtility.sendMessage(player, "You have already opened todays advent calendar door on this account."); + return; + } + + if (player.getMailbox().size() + calculateMailCount(player, todaysRewards) > 100) { + PacketSendUtility.sendMessage(player, "You have not enough room in your mailbox."); + return; + } + + if (!AdventDAO.storeLastReceivedDay(player, day)) { + PacketSendUtility.sendMessage(player, "Sorry. Some shugo broke our database, please report this in our bugtracker :("); + return; + } + + for (CustomSurveyItem item : todaysRewards) { + ItemTemplate template = DataManager.ITEM_DATA.getItemTemplate(item.getId()); + if (template != null && template.getRace() == player.getOppositeRace()) + continue; + long maxStackCount = template.getMaxStackCount(); + if (item.getCount() <= maxStackCount) { + sendRewardMail(player, item.getId(), item.getCount(), day); + continue; + } + int remainingItemCount = item.getCount(); + while (remainingItemCount > maxStackCount) { + remainingItemCount -= maxStackCount; + sendRewardMail(player, item.getId(), (int) maxStackCount, day); + } + sendRewardMail(player, item.getId(), remainingItemCount, day); + } + } + + private int calculateMailCount(Player player, List rewards) { + int expectedMailCount = 0; + for (CustomSurveyItem reward : rewards) { + int itemId = reward.getId(); + ItemTemplate itemTemplate = DataManager.ITEM_DATA.getItemTemplate(itemId); + if (itemTemplate == null || itemTemplate.getRace() == player.getOppositeRace()) + continue; + if (reward.getCount() <= itemTemplate.getMaxStackCount()) { + expectedMailCount++; + continue; + } + long maxStackCount = itemTemplate.getMaxStackCount(); + int remainingItemCount = reward.getCount(); + while (remainingItemCount >= maxStackCount) { + expectedMailCount++; + remainingItemCount -= maxStackCount; + } + } + return expectedMailCount; + } + + private void sendRewardMail(Player player, int itemId, int count, int day) { + SystemMailService.sendMail("Beyond Aion", player.getName(), "Advent Calendar", + "Greetings Daeva!\n\nToday is December " + day + + " and you know what that means! Another day, another advent calendar door.\n\nWe hope you can use this well~\n\n-Beyond Aion", + itemId, count, 0, LetterType.EXPRESS); + } + + public void showTodaysReward(Player player) { + ZonedDateTime now = ServerTime.now(); + int day = now.getDayOfMonth(); + List todaysRewards = rewards.get(day); + if (now.getMonth() != Month.DECEMBER || todaysRewards == null || todaysRewards.isEmpty()) { + PacketSendUtility.sendMessage(player, "There is no advent calendar door for today."); + return; + } + + StringBuilder sb = new StringBuilder("Todays advent calendar reward(s):\n"); + + for (Iterator iter = todaysRewards.iterator(); iter.hasNext();) { + int id = iter.next().getId(); + ItemTemplate template = DataManager.ITEM_DATA.getItemTemplate(id); + if (template != null && template.getRace() == player.getOppositeRace()) + continue; + sb.append(ChatUtil.item(id)).append(iter.hasNext() ? ", " : ""); + } + PacketSendUtility.sendMessage(player, sb.toString()); + } + + public static AdventService getInstance() { + return instance; + } +}