package com.eu.habbo.habbohotel.users.subscriptions; import com.eu.habbo.Emulator; import com.eu.habbo.database.Database; import com.eu.habbo.habbohotel.achievements.Achievement; import com.eu.habbo.habbohotel.achievements.AchievementManager; import com.eu.habbo.habbohotel.messenger.Messenger; import com.eu.habbo.habbohotel.rooms.RoomManager; import com.eu.habbo.habbohotel.users.Habbo; import com.eu.habbo.habbohotel.users.HabboInfo; import com.eu.habbo.habbohotel.users.HabboStats; import com.eu.habbo.habbohotel.users.clothingvalidation.ClothingValidationManager; import com.eu.habbo.messages.outgoing.catalog.ClubCenterDataComposer; import com.eu.habbo.messages.outgoing.generic.PickMonthlyClubGiftNotificationComposer; import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer; import com.eu.habbo.messages.outgoing.users.*; import gnu.trove.map.hash.THashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.TreeMap; /** * @author Beny */ public class SubscriptionHabboClub extends Subscription { private static final Logger LOGGER = LoggerFactory.getLogger(SubscriptionHabboClub.class); public static boolean HC_PAYDAY_ENABLED = false; public static int HC_PAYDAY_NEXT_DATE = Integer.MAX_VALUE; // yyyy-MM-dd HH:mm:ss public static String HC_PAYDAY_INTERVAL = ""; public static String HC_PAYDAY_QUERY = ""; public static TreeMap HC_PAYDAY_STREAK = new TreeMap<>(); public static String HC_PAYDAY_CURRENCY = ""; public static Double HC_PAYDAY_KICKBACK_PERCENTAGE = 0.1; public static String ACHIEVEMENT_NAME = ""; public static boolean DISCOUNT_ENABLED = false; public static int DISCOUNT_DAYS_BEFORE_END = 7; /** * When true "coins spent" will be calculated from the timestamp the user joins HC instead of from the last HC pay day execution timestamp */ public static boolean HC_PAYDAY_COINSSPENT_RESET_ON_EXPIRE = false; /** * Boolean indicating if HC pay day currency executing. Prevents double execution */ public static boolean isExecuting = false; public SubscriptionHabboClub(Integer id, Integer userId, String subscriptionType, Integer timestampStart, Integer duration, Boolean active) { super(id, userId, subscriptionType, timestampStart, duration, active); } /** * Called when the subscription is first created. * Actions: * - Set user's max_friends to MAXIMUM_FRIENDS_HC * - Set user's max_rooms to MAXIMUM_ROOMS_HC * - Reset the user's HC pay day timer (used in calculating the coins spent) * - Send associated HC packets to client */ @Override public void onCreated() { super.onCreated(); HabboInfo habboInfo = Emulator.getGameEnvironment().getHabboManager().getHabboInfo(this.getUserId()); HabboStats stats = habboInfo.getHabboStats(); stats.maxFriends = Messenger.MAXIMUM_FRIENDS_HC; stats.maxRooms = RoomManager.MAXIMUM_ROOMS_HC; stats.lastHCPayday = HC_PAYDAY_COINSSPENT_RESET_ON_EXPIRE ? Emulator.getIntUnixTimestamp() : HC_PAYDAY_NEXT_DATE - Emulator.timeStringToSeconds(HC_PAYDAY_INTERVAL); Emulator.getThreading().run(stats); progressAchievement(habboInfo); Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(this.getUserId()); if (habbo != null && habbo.getClient() != null) { if (habbo.getHabboStats().getRemainingClubGifts() > 0) { habbo.getClient().sendResponse(new PickMonthlyClubGiftNotificationComposer(habbo.getHabboStats().getRemainingClubGifts())); } if ((Emulator.getIntUnixTimestamp() - habbo.getHabboStats().hcMessageLastModified) < 60) { Emulator.getThreading().run(() -> { habbo.getClient().sendResponse(new UserClubComposer(habbo)); habbo.getClient().sendResponse(new UserPermissionsComposer(habbo)); }, (Emulator.getIntUnixTimestamp() - habbo.getHabboStats().hcMessageLastModified)); } else { habbo.getClient().sendResponse(new UserClubComposer(habbo, SubscriptionHabboClub.HABBO_CLUB, UserClubComposer.RESPONSE_TYPE_NORMAL)); habbo.getClient().sendResponse(new UserPermissionsComposer(habbo)); } } } /** * Called when the subscription is extended by manual action (by admin command or RCON) * Actions: * - Extend duration of the subscription * - Send associated HC packets to client */ @Override public void addDuration(int amount) { super.addDuration(amount); if (amount < 0) { Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(this.getUserId()); if (habbo != null && habbo.getClient() != null) { habbo.getClient().sendResponse(new UserClubComposer(habbo, SubscriptionHabboClub.HABBO_CLUB, UserClubComposer.RESPONSE_TYPE_NORMAL)); habbo.getClient().sendResponse(new UserPermissionsComposer(habbo)); } } } /** * Called when the subscription is extended or bought again when already exists * Actions: * - Extend duration of the subscription * - Send associated HC packets to client */ @Override public void onExtended(int duration) { super.onExtended(duration); Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(this.getUserId()); if (habbo != null && habbo.getClient() != null) { habbo.getClient().sendResponse(new UserClubComposer(habbo, SubscriptionHabboClub.HABBO_CLUB, UserClubComposer.RESPONSE_TYPE_NORMAL)); habbo.getClient().sendResponse(new UserPermissionsComposer(habbo)); } } /** * Called by SubscriptionScheduler when isActive() && getRemaining() < 0 * Actions: * - Set user's max_friends to MAXIMUM_FRIENDS * - Set user's max_rooms to MAXIMUM_ROOMS * - Remove HC clothing * - Send associated HC packets to client */ @Override public void onExpired() { super.onExpired(); Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(this.getUserId()); HabboInfo habboInfo = Emulator.getGameEnvironment().getHabboManager().getHabboInfo(this.getUserId()); HabboStats stats = habboInfo.getHabboStats(); stats.maxFriends = Messenger.MAXIMUM_FRIENDS; stats.maxRooms = RoomManager.MAXIMUM_ROOMS_USER; Emulator.getThreading().run(stats); if (habbo != null && ClothingValidationManager.VALIDATE_ON_HC_EXPIRE) { habboInfo.setLook(ClothingValidationManager.validateLook(habbo, habboInfo.getLook(), habboInfo.getGender().name())); Emulator.getThreading().run(habbo.getHabboInfo()); if (habbo.getClient() != null) { habbo.getClient().sendResponse(new UpdateUserLookComposer(habbo)); } if (habbo.getHabboInfo().getCurrentRoom() != null) { habbo.getHabboInfo().getCurrentRoom().sendComposer(new RoomUserDataComposer(habbo).compose()); } } if (habbo != null && habbo.getClient() != null) { habbo.getClient().sendResponse(new UserClubComposer(habbo, SubscriptionHabboClub.HABBO_CLUB, UserClubComposer.RESPONSE_TYPE_NORMAL)); habbo.getClient().sendResponse(new UserPermissionsComposer(habbo)); } } /** * Calculate's a users upcoming HC Pay day rewards * * @param habbo User to calculate for * @return ClubCenterDataComposer */ public static ClubCenterDataComposer calculatePayday(HabboInfo habbo) { Subscription activeSub = null; Subscription firstEverSub = null; int currentHcStreak = 0; int totalCreditsSpent = 0; int creditRewardForStreakBonus = 0; int creditRewardForMonthlySpent = 0; int timeUntilPayday = 0; for (Subscription sub : habbo.getHabboStats().subscriptions) { if (sub.getSubscriptionType().equalsIgnoreCase(Subscription.HABBO_CLUB)) { if (firstEverSub == null || sub.getTimestampStart() < firstEverSub.getTimestampStart()) { firstEverSub = sub; } if (sub.isActive()) { activeSub = sub; } } } if (HC_PAYDAY_ENABLED && activeSub != null) { currentHcStreak = (int) Math.floor((Emulator.getIntUnixTimestamp() - activeSub.getTimestampStart()) / (60 * 60 * 24.0)); if (currentHcStreak < 1) { currentHcStreak = 0; } for (Map.Entry set : HC_PAYDAY_STREAK.entrySet()) { if (currentHcStreak >= set.getKey() && set.getValue() > creditRewardForStreakBonus) { creditRewardForStreakBonus = set.getValue(); } } THashMap queryParams = new THashMap(); queryParams.put("@user_id", habbo.getId()); queryParams.put("@timestamp_start", habbo.getHabboStats().lastHCPayday); queryParams.put("@timestamp_end", HC_PAYDAY_NEXT_DATE); try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = Database.preparedStatementWithParams(connection, HC_PAYDAY_QUERY, queryParams)) { try (ResultSet set = statement.executeQuery()) { while (set.next()) { totalCreditsSpent = set.getInt("amount_spent"); } } } catch (SQLException e) { SubscriptionManager.LOGGER.error("Caught SQL exception", e); } creditRewardForMonthlySpent = (int) Math.floor(totalCreditsSpent * HC_PAYDAY_KICKBACK_PERCENTAGE); timeUntilPayday = (HC_PAYDAY_NEXT_DATE - Emulator.getIntUnixTimestamp()) / 60; } return new ClubCenterDataComposer( currentHcStreak, (firstEverSub != null ? new SimpleDateFormat("dd-MM-yyyy").format(new Date(firstEverSub.getTimestampStart() * 1000L)) : ""), HC_PAYDAY_KICKBACK_PERCENTAGE, 0, 0, totalCreditsSpent, creditRewardForStreakBonus, creditRewardForMonthlySpent, timeUntilPayday ); } /** * Executes the HC Pay day, calculating reward for all active HABBO_CLUB subscribers and issuing rewards. */ public static void executePayDay() { isExecuting = true; int timestampNow = Emulator.getIntUnixTimestamp(); try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT user_id FROM `users_subscriptions` WHERE subscription_type = '" + Subscription.HABBO_CLUB + "' AND `active` = 1 AND `timestamp_start` < ? AND (`timestamp_start` + `duration`) > ? GROUP BY user_id")) { statement.setInt(1, timestampNow); statement.setInt(2, timestampNow); try (ResultSet set = statement.executeQuery()) { while (set.next()) { try { int userId = set.getInt("user_id"); HabboInfo habboInfo = Emulator.getGameEnvironment().getHabboManager().getHabboInfo(userId); HabboStats stats = habboInfo.getHabboStats(); ClubCenterDataComposer calculated = calculatePayday(habboInfo); int totalReward = (calculated.creditRewardForMonthlySpent + calculated.creditRewardForStreakBonus); if (totalReward > 0) { boolean claimed = claimPayDay(Emulator.getGameEnvironment().getHabboManager().getHabbo(userId), totalReward, HC_PAYDAY_CURRENCY); HcPayDayLogEntry le = new HcPayDayLogEntry(timestampNow, userId, calculated.currentHcStreak, calculated.totalCreditsSpent, calculated.creditRewardForMonthlySpent, calculated.creditRewardForStreakBonus, totalReward, HC_PAYDAY_CURRENCY, claimed); Emulator.getThreading().run(le); } stats.lastHCPayday = timestampNow; Emulator.getThreading().run(stats); } catch (Exception e) { SubscriptionManager.LOGGER.error("Exception processing HC payday for user #" + set.getInt("user_id"), e); } } } Date date = new java.util.Date(HC_PAYDAY_NEXT_DATE * 1000L); date = Emulator.modifyDate(date, HC_PAYDAY_INTERVAL); HC_PAYDAY_NEXT_DATE = (int) (date.getTime() / 1000L); try (PreparedStatement stm2 = connection.prepareStatement("UPDATE `emulator_settings` SET `value` = ? WHERE `key` = ?")) { SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); stm2.setString(1, sdf.format(date)); stm2.setString(2, "subscriptions.hc.payday.next_date"); stm2.execute(); } try (PreparedStatement stm2 = connection.prepareStatement("UPDATE users_settings SET last_hc_payday = ? WHERE user_id IN (SELECT user_id FROM `users_subscriptions` WHERE subscription_type = '" + Subscription.HABBO_CLUB + "' AND `active` = 1 AND `timestamp_start` < ? AND (`timestamp_start` + `duration`) > ? GROUP BY user_id)")) { stm2.setInt(1, timestampNow); stm2.setInt(2, timestampNow); stm2.setInt(3, timestampNow); stm2.execute(); } } catch (SQLException e) { SubscriptionManager.LOGGER.error("Caught SQL exception", e); } isExecuting = false; } /** * Called when a user logs in. Checks for any unclaimed HC Pay day rewards and issues rewards. * * @param habbo User to process */ public static void processUnclaimed(Habbo habbo) { progressAchievement(habbo.getHabboInfo()); if (habbo.getHabboStats().getRemainingClubGifts() > 0) { habbo.getClient().sendResponse(new PickMonthlyClubGiftNotificationComposer(habbo.getHabboStats().getRemainingClubGifts())); } try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT * FROM `logs_hc_payday` WHERE user_id = ? AND claimed = 0")) { statement.setInt(1, habbo.getHabboInfo().getId()); try (ResultSet set = statement.executeQuery()) { while (set.next()) { try { int logId = set.getInt("id"); int userId = set.getInt("user_id"); int totalPayout = set.getInt("total_payout"); String currency = set.getString("currency"); if (claimPayDay(habbo, totalPayout, currency)) { try (PreparedStatement stm2 = connection.prepareStatement("UPDATE logs_hc_payday SET claimed = 1 WHERE id = ?")) { stm2.setInt(1, logId); stm2.execute(); } } } catch (Exception e) { SubscriptionManager.LOGGER.error("Exception processing HC payday for user #" + set.getInt("user_id"), e); } } } } catch (SQLException e) { SubscriptionManager.LOGGER.error("Caught SQL exception", e); } } /** * * Seperated these because Beny shouldn't have tied them to Payday. */ public static void processClubBadge(Habbo habbo) { progressAchievement(habbo.getHabboInfo()); } /** * Issues rewards to user. * @param habbo User to reward to * @param amount Amount of currency to reward * @param currency Currency string (Can be one of: credits, diamonds, duckets, pixels or a currency ID e.g. 5) * @return Boolean indicating success of the operation */ public static boolean claimPayDay(Habbo habbo, int amount, String currency) { if(habbo == null) return false; int pointCurrency; switch(currency.toLowerCase()) { case "credits": case "coins": case "credit": case "coin": habbo.getClient().getHabbo().giveCredits(amount); break; case "diamonds": case "diamond": pointCurrency = 5; habbo.getClient().getHabbo().givePoints(pointCurrency, amount); break; case "duckets": case "ducket": case "pixels": case "pixel": pointCurrency = 0; habbo.getClient().getHabbo().givePoints(pointCurrency, amount); break; default: pointCurrency = -1; try { pointCurrency = Integer.parseInt(currency); } catch (NumberFormatException ex) { LOGGER.error("Couldn't convert the type point currency {} on HC PayDay. The number must be a integer and positive.", pointCurrency); } if (pointCurrency >= 0) { habbo.getClient().getHabbo().givePoints(pointCurrency, amount); } break; } habbo.alert(Emulator.getTexts().getValue("subscriptions.hc.payday.message", "Woohoo HC Payday has arrived! You have received %amount% credits to your purse. Enjoy!").replace("%amount%", "" + amount)); return true; } private static void progressAchievement(HabboInfo habboInfo) { HabboStats stats = habboInfo.getHabboStats(); Achievement achievement = Emulator.getGameEnvironment().getAchievementManager().getAchievement(ACHIEVEMENT_NAME); if(achievement != null) { int currentProgress = stats.getAchievementProgress(achievement); if(currentProgress == -1) { currentProgress = 0; } int progressToSet = (int)Math.ceil(stats.getPastTimeAsClub() / 2678400.0); int toIncrease = Math.max(progressToSet - currentProgress, 0); if(toIncrease > 0) { AchievementManager.progressAchievement(habboInfo.getId(), achievement, toIncrease); } } } }