Addition of VIP system.

Contributed by marciox25.
This commit is contained in:
MobiusDevelopment
2021-04-30 16:29:22 +00:00
parent f7b82e35b9
commit 1acb57e53f
331 changed files with 16039 additions and 487 deletions

View File

@@ -13,6 +13,10 @@ EnableAttendanceRewards = False
# Default: False
PremiumOnlyAttendanceRewards = False
# Enable the Attendance Reward system only for Vip accounts.
# Default: False
VipOnlyAttendanceRewards = False
# Make rewards sharable in the same account.
# Default: False (Each character will receive its own rewards.)
AttendanceRewardsShareAccount = False

View File

@@ -9,6 +9,9 @@ PcCafeEnabled = False
# Allow only players with a Premium account.
PcCafeOnlyPremium = False
# Allow only players with a Vip Tier account.
PcCafeOnlyVip = False
# Max points that player may have.
# Limited by int limit.
MaxPcCafePoints = 200000

View File

@@ -0,0 +1,26 @@
# ---------------------------------------------------------------------------
# VIP System
# ---------------------------------------------------------------------------
# VIP System Enabled.
# l2.ini
# [VipSystem]
# UseVipInfoWnd=true
# -> needs to be true
# Prime shop needs to be true aswell!
# Check vip.xml for more info!
VipEnabled = False
# Max vip level that can be reached (Client Limitations, lv 8 -> 10 Doesn't exist. If u want to use, make it yourself!)
MaxVipLevel = 7
# When purchasing from the Prime Shop, the price amount will add to your vip points
PrimeAffectPoints = true
# Drop Amount of Silver coins if the Vip Tier allows it
VipSilverDropMin = 1
VipSilverDropMax = 5
# Drop Amount of Golden coins if the Vip Tier allows it
VipGoldenDropMin = 1
VipGoldenDropMax = 5

View File

@@ -1,3 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<list enabled="false" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/PrimeShop.xsd">
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/PrimeShop.xsd">
<!--
cat 11 = supplies
cat 12 = Equipment/outfit
cat 13 = VIP
cat 14 = Event
cat 15 = Reward Coins
On Cat 15, golden coins use the same value as "price" and silver uses the value from silverCoin node. -> paymenttype = 0
for the price to be used as golden or silver, vipTier needs to be > 0
-->
<item id="2090044" cat="11" paymentType="0" price="30" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0">
<item itemId="29505" count="1" /> <!-- Normal VIP Gain Scroll -->
</item>
<item id="2090045" cat="12" paymentType="0" price="60" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0">
<item itemId="29506" count="1" /> <!-- Medium VIP Gain Scroll -->
</item>
<item id="2090046" cat="13" paymentType="0" price="50" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0">
<item itemId="29507" count="1" /> <!-- Good VIP Gain Scroll -->
</item>
<item id="2090047" cat="14" paymentType="0" price="100" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0">
<item itemId="29508" count="1" /> <!-- Perfect VIP Gain Scroll -->
</item>
<item id="2090048" cat="15" paymentType="0" price="0" silverCoin="100" recommended="4" vipTier="7" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0">
<item itemId="29505" count="1" /> <!-- Normal VIP Gain Scroll -->
</item>
<item id="2090049" cat="15" paymentType="0" price="0" silverCoin="200" recommended="4" vipTier="7" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0">
<item itemId="29506" count="1" /> <!-- Medium VIP Gain Scroll -->
</item>
<item id="2090050" cat="15" paymentType="0" price="50" silverCoin="0" recommended="4" vipTier="7" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0">
<item itemId="29507" count="1" /> <!-- Good VIP Gain Scroll -->
</item>
<item id="2090051" cat="15" paymentType="0" price="100" silverCoin="0" recommended="4" vipTier="7" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0">
<item itemId="29508" count="1" /> <!-- Perfect VIP Gain Scroll -->
</item>
<item id="100001" cat="13" paymentType="0" price="0" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0" isVipGift="true" vipTier="1">
<item itemId="29001" count="1" /> <!-- Daily Present - VIP 1 -->
</item>
<item id="100002" cat="13" paymentType="0" price="0" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0" isVipGift="true" vipTier="2">
<item itemId="29002" count="1" /> <!-- Daily Present - VIP 2 -->
</item>
<item id="100003" cat="13" paymentType="0" price="0" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0" isVipGift="true" vipTier="3">
<item itemId="29003" count="1" /> <!-- Daily Present - VIP 3 -->
</item>
<item id="100004" cat="13" paymentType="0" price="0" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0" isVipGift="true" vipTier="4">
<item itemId="29004" count="1" /> <!-- Daily Present - VIP 4 -->
</item>
<item id="100005" cat="13" paymentType="0" price="0" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0" isVipGift="true" vipTier="5">
<item itemId="29005" count="1" /> <!-- Daily Present - VIP 5 -->
</item>
<item id="100006" cat="13" paymentType="0" price="0" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0" isVipGift="true" vipTier="6">
<item itemId="29006" count="1" /> <!-- Daily Present - VIP 6 -->
</item>
<item id="100007" cat="13" paymentType="0" price="0" recommended="4" startSale="315558000" endSale="2127452400" dayOfWeek="127" startHour="0" startMinute="0" stopHour="23" stopMinute="59" stock="-1" maxStock="-1" salePercent="0" minLevel="0" maxLevel="0" minBirthday="0" maxBirthday="0" restrictionDay="0" availableCount="0" isVipGift="true" vipTier="7">
<item itemId="29007" count="1" /> <!-- Daily Present - VIP 7 -->
</item>
</list>

View File

@@ -382,6 +382,7 @@ public class EffectMasterHandler
EffectHandler.getInstance().registerHandler("Untargetable", Untargetable::new);
EffectHandler.getInstance().registerHandler("VampiricAttack", VampiricAttack::new);
EffectHandler.getInstance().registerHandler("VampiricDefence", VampiricDefence::new);
EffectHandler.getInstance().registerHandler("VipUp", VipUp::new);
EffectHandler.getInstance().registerHandler("VitalityExpRate", VitalityExpRate::new);
EffectHandler.getInstance().registerHandler("VitalityPointsRate", VitalityPointsRate::new);
EffectHandler.getInstance().registerHandler("VitalityPointUp", VitalityPointUp::new);

View File

@@ -0,0 +1,60 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package handlers.effecthandlers;
import org.l2jmobius.gameserver.model.StatSet;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.effects.AbstractEffect;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.model.skills.Skill;
/**
* @author Gabriel Costa Souza
*/
public class VipUp extends AbstractEffect
{
private final long _amount;
public VipUp(StatSet params)
{
_amount = params.getLong("amount", 0L);
}
@Override
public boolean isInstant()
{
return true;
}
@Override
public void instant(Creature effector, Creature effected, Skill skill, ItemInstance item)
{
if (effected == null)
{
return;
}
final PlayerInstance player = effected.getActingPlayer();
if (player == null)
{
return;
}
player.updateVipPoints(_amount);
}
}

View File

@@ -73,46 +73,70 @@
<item id="29505" name="Normal VIP Gain Scroll" type="EtcItem">
<!-- Allows to regain 1 VIP Point when used. Cannot be exchanged, dropped or sold in a private store. Can be stored in a private warehouse. -->
<set name="icon" val="BranchIcon.Icon.g_bm_vip_potion_i00" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="material" val="PAPER" />
<set name="weight" val="5" />
<set name="is_stackable" val="true" />
<set name="is_tradable" val="false" />
<set name="is_dropable" val="false" />
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="etcitem_type" val="SCROLL" />
<set name="handler" val="ItemSkills" />
<set name="commissionItemType" val="SCROLL_OTHER" />
<set name="material" val="PAPER" />
<skills>
<skill id="55322" level="1" /> <!-- Normal VIP Gain Scroll -->
</skills>
</item>
<item id="29506" name="Medium VIP Gain Scroll" type="EtcItem">
<!-- Allows to regain 10 VIP Points when used. Cannot be exchanged, dropped or sold in a private store. Can be stored in a private warehouse. -->
<set name="icon" val="BranchIcon.Icon.g_bm_vip_potion_i00" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="material" val="PAPER" />
<set name="weight" val="5" />
<set name="is_stackable" val="true" />
<set name="is_tradable" val="false" />
<set name="is_dropable" val="false" />
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="etcitem_type" val="SCROLL" />
<set name="handler" val="ItemSkills" />
<set name="commissionItemType" val="SCROLL_OTHER" />
<set name="material" val="PAPER" />
<skills>
<skill id="55323" level="1" /> <!-- Medium VIP Gain Scroll -->
</skills>
</item>
<item id="29507" name="Good VIP Gain Scroll" type="EtcItem">
<!-- Allows to regain 100 VIP Points when used. Cannot be exchanged, dropped or sold in a private store. Can be stored in a private warehouse. -->
<set name="icon" val="BranchIcon.Icon.g_bm_vip_potion_i00" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="material" val="PAPER" />
<set name="weight" val="5" />
<set name="is_stackable" val="true" />
<set name="is_tradable" val="false" />
<set name="is_dropable" val="false" />
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="etcitem_type" val="SCROLL" />
<set name="handler" val="ItemSkills" />
<set name="commissionItemType" val="SCROLL_OTHER" />
<set name="material" val="PAPER" />
<skills>
<skill id="55324" level="1" /> <!-- Good VIP Gain Scroll -->
</skills>
</item>
<item id="29508" name="Perfect VIP Gain Scroll" type="EtcItem">
<!-- Allows to regain 280 VIP Points when used. Cannot be exchanged, dropped or sold in a private store. Can be stored in a private warehouse. -->
<set name="icon" val="BranchIcon.Icon.g_bm_vip_potion_i00" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="material" val="PAPER" />
<set name="weight" val="5" />
<set name="is_stackable" val="true" />
<set name="is_tradable" val="false" />
<set name="is_dropable" val="false" />
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="etcitem_type" val="SCROLL" />
<set name="handler" val="ItemSkills" />
<set name="commissionItemType" val="SCROLL_OTHER" />
<set name="material" val="PAPER" />
<skills>
<skill id="55325" level="1" /> <!-- Perfect VIP Gain Scroll -->
</skills>
</item>
<item id="29509" name="Feather of Blessing (temporary used by NPC)" type="EtcItem">
<!-- Dimensional item. Blessed feather that allows to resurrect right in the place of death. -->

View File

@@ -283,36 +283,327 @@
<!-- The right to VIP 1st level chest. Acquired XP/ SP +3%, item drop rate +3%. -->
<icon>BranchIcon.Icon.g_skill_vip1</icon>
<operateType>P</operateType>
<hitTime>500</hitTime>
<effects>
<effect name="ExpModify">
<amount>3</amount>
</effect>
<effect name="SpModify">
<amount>3</amount>
</effect>
<effect name="BonusDropRate">
<amount>50</amount>
<mode>PER</mode>
</effect>
</effects>
</skill>
<skill id="55025" toLevel="1" name="VIP Level 2">
<!-- The right to VIP 2nd level chest. Acquired XP/ SP +7%, item drop rate +7%. World chat on any level, number of usage attempts +10. -->
<icon>BranchIcon.Icon.g_skill_vip2</icon>
<operateType>P</operateType>
<hitTime>500</hitTime>
<effects>
<effect name="ExpModify">
<amount>7</amount>
</effect>
<effect name="SpModify">
<amount>7</amount>
</effect>
<effect name="BonusDropRate">
<amount>150</amount>
<mode>PER</mode>
</effect>
<effect name="WorldChatPoints">
<amount>3</amount>
<mode>DIFF</mode>
</effect>
</effects>
</skill>
<skill id="55026" toLevel="1" name="VIP Level 3">
<!-- The right to VIP 3rd level chest. Acquired XP/ SP +15%, item drop rate +15%. Experience loss and chance to lose items upon death is -10%. World chat on any level, number of usage attempts +10. -->
<icon>BranchIcon.Icon.g_skill_vip3</icon>
<operateType>P</operateType>
<hitTime>500</hitTime>
<effects>
<effect name="ExpModify">
<amount>15</amount>
</effect>
<effect name="SpModify">
<amount>15</amount>
</effect>
<effect name="BonusDropRate">
<amount>200</amount>
<mode>PER</mode>
</effect>
<effect name="WorldChatPoints">
<amount>3</amount>
<mode>DIFF</mode>
</effect>
</effects>
</skill>
<skill id="55027" toLevel="1" name="VIP Level 4">
<!-- The right to VIP 4th level chest. Acquired XP/ SP +25%, item drop rate +15%. Experience loss and chance to lose items upon death is -15%. World chat on any level, number of usage attempts +10. -->
<icon>BranchIcon.Icon.g_skill_vip4</icon>
<operateType>P</operateType>
<hitTime>500</hitTime>
<effects>
<effect name="ExpModify">
<amount>25</amount>
</effect>
<effect name="SpModify">
<amount>25</amount>
</effect>
<effect name="FishingExpSpBonus">
<amount>20</amount>
<mode>PER</mode>
</effect>
<effect name="BonusDropRate">
<amount>250</amount>
<mode>PER</mode>
</effect>
<effect name="WorldChatPoints">
<amount>5</amount>
<mode>DIFF</mode>
</effect>
<effect name="ReduceDropPenalty">
<deathPenalty>-15</deathPenalty>
<mode>PER</mode>
</effect>
</effects>
</skill>
<skill id="55028" toLevel="1" name="VIP Level 5">
<!-- The right to VIP 5th level chest. Acquired XP/ SP +30%, item drop rate +30%. Experience loss and chance to lose items upon death -20%. PvE damage is increased. World chat on any level, number of usage attempts +10. -->
<icon>BranchIcon.Icon.g_skill_vip5</icon>
<operateType>P</operateType>
<hitTime>500</hitTime>
<effects>
<effect name="ExpModify">
<amount>30</amount>
</effect>
<effect name="SpModify">
<amount>30</amount>
</effect>
<effect name="BonusDropRate">
<amount>250</amount>
<mode>PER</mode>
</effect>
<effect name="WorldChatPoints">
<amount>10</amount>
<mode>DIFF</mode>
</effect>
<effect name="ReduceDropPenalty">
<deathPenalty>-20</deathPenalty>
<mode>PER</mode>
</effect>
<effect name="PveMagicalSkillDamageBonus">
<amount>10</amount>
<mode>PER</mode>
</effect>
<effect name="PvePhysicalAttackDamageBonus">
<amount>10</amount>
<mode>PER</mode>
</effect>
<effect name="PvePhysicalSkillDamageBonus">
<amount>10</amount>
<mode>PER</mode>
</effect>
<effect name="PvePhysicalSkillDamageBonus">
<amount>10</amount>
<mode>PER</mode>
</effect>
<effect name="PveRaidMagicalSkillDamageBonus">
<amount>10</amount>
<mode>PER</mode>
</effect>
<effect name="PveRaidPhysicalAttackDamageBonus">
<amount>10</amount>
<mode>PER</mode>
</effect>
<effect name="PveRaidPhysicalSkillDamageBonus">
<amount>10</amount>
<mode>PER</mode>
</effect>
<effect name="FishingExpSpBonus">
<amount>20</amount>
<mode>PER</mode>
</effect>
</effects>
</skill>
<skill id="55029" toLevel="1" name="VIP Level 6">
<!-- The right to VIP 6th level chest. Acquired XP/ SP +30%, item drop rate +30%. Experience loss and chance to lose items upon death -20%. PvE damage is increased, STR/ DEX/ CON/ INT/ WIT/ MEN +2. World chat on any level, number of usage attempts +10. -->
<icon>BranchIcon.Icon.g_skill_vip6</icon>
<operateType>P</operateType>
<hitTime>500</hitTime>
<effects>
<effect name="ExpModify">
<amount>30</amount>
</effect>
<effect name="SpModify">
<amount>30</amount>
</effect>
<effect name="BonusDropRate">
<amount>250</amount>
<mode>PER</mode>
</effect>
<effect name="WorldChatPoints">
<amount>10</amount>
<mode>DIFF</mode>
</effect>
<effect name="ReduceDropPenalty">
<deathPenalty>-20</deathPenalty>
<mode>PER</mode>
</effect>
<effect name="PveMagicalSkillDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PvePhysicalAttackDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PvePhysicalSkillDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PvePhysicalSkillDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PveRaidMagicalSkillDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PveRaidPhysicalAttackDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PveRaidPhysicalSkillDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="FishingExpSpBonus">
<amount>20</amount>
<mode>PER</mode>
</effect>
<effect name="StatUp">
<amount>1</amount>
<stat>STR</stat>
</effect>
<effect name="StatUp">
<amount>1</amount>
<stat>INT</stat>
</effect>
<effect name="StatUp">
<amount>1</amount>
<stat>CON</stat>
</effect>
<effect name="StatUp">
<amount>1</amount>
<stat>DEX</stat>
</effect>
<effect name="StatUp">
<amount>1</amount>
<stat>MEN</stat>
</effect>
<effect name="StatUp">
<amount>1</amount>
<stat>WIT</stat>
</effect>
</effects>
</skill>
<skill id="55030" toLevel="1" name="VIP Level 7">
<!-- The right to VIP 7th level chest. Acquired XP/ SP +30%, item drop rate +30%. Experience loss and chance to lose items upon death -20%. PvE/ PvP damage is increased, STR/ DEX/ CON/ INT/ WIT/ MEN +2. World chat on any level, number of usage attempts +10. -->
<icon>BranchIcon.Icon.g_skill_vip7</icon>
<operateType>P</operateType>
<hitTime>500</hitTime>
<effects>
<effect name="ExpModify">
<amount>30</amount>
</effect>
<effect name="SpModify">
<amount>30</amount>
</effect>
<effect name="BonusDropRate">
<amount>250</amount>
<mode>PER</mode>
</effect>
<effect name="WorldChatPoints">
<amount>10</amount>
<mode>DIFF</mode>
</effect>
<effect name="ReduceDropPenalty">
<deathPenalty>-20</deathPenalty>
<mode>PER</mode>
</effect>
<effect name="PveMagicalSkillDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PvePhysicalAttackDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PvePhysicalSkillDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PvePhysicalSkillDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PveRaidMagicalSkillDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PveRaidPhysicalAttackDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PveRaidPhysicalSkillDamageBonus">
<amount>15</amount>
<mode>PER</mode>
</effect>
<effect name="PvpMagicalSkillDamageBonus">
<amount>5</amount>
<mode>PER</mode>
</effect>
<effect name="PvpPhysicalAttackDamageBonus">
<amount>5</amount>
<mode>PER</mode>
</effect>
<effect name="PvpPhysicalSkillDamageBonus">
<amount>5</amount>
<mode>PER</mode>
</effect>
<effect name="FishingExpSpBonus">
<amount>20</amount>
<mode>PER</mode>
</effect>
<effect name="StatUp">
<amount>2</amount>
<stat>STR</stat>
</effect>
<effect name="StatUp">
<amount>2</amount>
<stat>INT</stat>
</effect>
<effect name="StatUp">
<amount>2</amount>
<stat>CON</stat>
</effect>
<effect name="StatUp">
<amount>2</amount>
<stat>DEX</stat>
</effect>
<effect name="StatUp">
<amount>2</amount>
<stat>MEN</stat>
</effect>
<effect name="StatUp">
<amount>2</amount>
<stat>WIT</stat>
</effect>
</effects>
</skill>
<skill id="55031" toLevel="1" name="Report Status">
<!-- You are under suspicion of using this program illegally. Your actions have been restricted. -->

View File

@@ -741,21 +741,41 @@
<icon>BranchIcon.Icon.g_bm_vip_potion_i00</icon>
<operateType>A1</operateType>
<reuseDelay>1000</reuseDelay>
<effects>
<effect name="VipUp">
<amount>1</amount>
</effect>
</effects>
</skill>
<skill id="55323" toLevel="1" name="Medium VIP Gain Scroll">
<icon>BranchIcon.Icon.g_bm_vip_potion_i00</icon>
<operateType>A1</operateType>
<reuseDelay>1000</reuseDelay>
<effects>
<effect name="VipUp">
<amount>10</amount>
</effect>
</effects>
</skill>
<skill id="55324" toLevel="1" name="Good VIP Gain Scroll">
<icon>BranchIcon.Icon.g_bm_vip_potion_i00</icon>
<operateType>A1</operateType>
<reuseDelay>1000</reuseDelay>
<effects>
<effect name="VipUp">
<amount>100</amount>
</effect>
</effects>
</skill>
<skill id="55325" toLevel="1" name="Perfect VIP Gain Scroll">
<icon>BranchIcon.Icon.g_bm_vip_potion_i00</icon>
<operateType>A1</operateType>
<reuseDelay>1000</reuseDelay>
<effects>
<effect name="VipUp">
<amount>280</amount>
</effect>
</effects>
</skill>
<skill id="55326" toLevel="1" name="Gold Fishing Shot">
<operateType>A1</operateType>

View File

@@ -0,0 +1,58 @@
<?xml version='1.0' encoding='utf-8'?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/vip.xsd">
<!--
tier: tier of the vip
points-requires: points required to get to that tier
points-lose: points player will lose after a while.
PS. Client data made for Sylph! Probably works on essence aswell! Might need to check for classic!.
l2.ini
[VipSystem]
UseVipInfoWnd=false
-> needs to be true
# Prime shop needs to be true aswell!
ProductName_Classic-eu.dat
44-47 -> L2 Point purchases
product_name_begin id=2090044 outer_name=[Normal VIP Gain Scroll] description=[] icon=[BranchIcon.Icon.g_bm_vip_potion_i00] icon_panel=[None] mainsubject=[] product_name_end
product_name_begin id=2090045 outer_name=[Medium VIP Gain Scroll] description=[] icon=[BranchIcon.Icon.g_bm_vip_potion_i00] icon_panel=[None] mainsubject=[] product_name_end
product_name_begin id=2090046 outer_name=[Good VIP Gain Scroll] description=[] icon=[BranchIcon.Icon.g_bm_vip_potion_i00] icon_panel=[None] mainsubject=[] product_name_end
product_name_begin id=2090047 outer_name=[Perfect VIP Gain Scroll] description=[] icon=[BranchIcon.Icon.g_bm_vip_potion_i00] icon_panel=[None] mainsubject=[] product_name_end
48-51 -> VIP Coin purchases
product_name_begin id=2090048 outer_name=[Normal VIP Gain Scroll] description=[] icon=[BranchIcon.Icon.g_bm_vip_potion_i00] icon_panel=[None] mainsubject=[] product_name_end
product_name_begin id=2090049 outer_name=[Medium VIP Gain Scroll] description=[] icon=[BranchIcon.Icon.g_bm_vip_potion_i00] icon_panel=[None] mainsubject=[] product_name_end
product_name_begin id=2090050 outer_name=[Good VIP Gain Scroll] description=[] icon=[BranchIcon.Icon.g_bm_vip_potion_i00] icon_panel=[None] mainsubject=[] product_name_end
product_name_begin id=2090051 outer_name=[Perfect VIP Gain Scroll] description=[] icon=[BranchIcon.Icon.g_bm_vip_potion_i00] icon_panel=[None] mainsubject=[] product_name_end
-->
<vip tier="0" points-required="0" points-lose="0">
<bonus/>
</vip>
<vip tier="1" points-required="300" points-lose="300">
<bonus skill="55024"/>
</vip>
<vip tier="2" points-required="1000" points-lose="600">
<bonus skill="55025"/>
</vip>
<vip tier="3" points-required="2000" points-lose="660">
<bonus skill="55026" silverChance="1.0" goldChance="1.0"/>
</vip>
<vip tier="4" points-required="3500" points-lose="1320">
<bonus skill="55027" silverChance="2.0" goldChance="2.0"/>
</vip>
<vip tier="5" points-required="7000" points-lose="2640">
<bonus skill="55028" silverChance="3.5" goldChance="3.5"/>
</vip>
<vip tier="6" points-required="20000" points-lose="5280">
<bonus skill="55029" silverChance="5.0" goldChance="5.0"/>
</vip>
<vip tier="7" points-required="40000" points-lose="10560">
<bonus skill="55030" silverChance="7.0" goldChance="7.0"/>
</vip>
</list>

View File

@@ -34,6 +34,9 @@
<xs:attribute type="xs:byte" name="maxBirthday" use="optional" />
<xs:attribute type="xs:byte" name="restrictionDay" use="optional" />
<xs:attribute type="xs:byte" name="availableCount" use="optional" />
<xs:attribute type="xs:boolean" name="isVipGift" use="optional" />
<xs:attribute type="xs:byte" name="vipTier" use="optional" />
<xs:attribute type="xs:int" name="silverCoin" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="list">
<xs:complexType>
<xs:sequence>
<xs:element name="vip" type="TierInfo" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="TierInfo">
<xs:sequence>
<xs:element name="bonus" type="TierBonusInfo"/>
</xs:sequence>
<xs:attribute name="tier" type="xs:byte" use="required"/>
<xs:attribute name="points-required" type="xs:long" use="required"/>
<xs:attribute name="points-lose" type="xs:long" use="required"/>
</xs:complexType>
<xs:complexType name="TierBonusInfo">
<xs:attribute name="silverChance" type="xs:float" default="0"/>
<xs:attribute name="goldChance" type="xs:float" default="0"/>
<xs:attribute name="skill" type="xs:int" default="0"/>
</xs:complexType>
</xs:schema>

View File

@@ -132,6 +132,7 @@ public class Config
private static final String CUSTOM_OFFLINE_TRADE_CONFIG_FILE = "./config/Custom/OfflineTrade.ini";
private static final String CUSTOM_PASSWORD_CHANGE_CONFIG_FILE = "./config/Custom/PasswordChange.ini";
private static final String CUSTOM_PC_CAFE_CONFIG_FILE = "./config/Custom/PcCafe.ini";
private static final String CUSTOM_VIP_CONFIG_FILE = "./config/Custom/VipSystem.ini";
private static final String CUSTOM_PREMIUM_SYSTEM_CONFIG_FILE = "./config/Custom/PremiumSystem.ini";
private static final String CUSTOM_PRIVATE_STORE_RANGE_CONFIG_FILE = "./config/Custom/PrivateStoreRange.ini";
private static final String CUSTOM_PVP_ANNOUNCE_CONFIG_FILE = "./config/Custom/PvpAnnounce.ini";
@@ -154,6 +155,7 @@ public class Config
public static boolean ENABLE_ATTENDANCE_REWARDS;
public static boolean PREMIUM_ONLY_ATTENDANCE_REWARDS;
public static boolean VIP_ONLY_ATTENDANCE_REWARDS;
public static boolean ATTENDANCE_REWARDS_SHARE_ACCOUNT;
public static int ATTENDANCE_REWARD_DELAY;
public static boolean ATTENDANCE_POPUP_START;
@@ -1235,6 +1237,7 @@ public class Config
public static boolean PREMIUM_ONLY_FISHING;
public static boolean PC_CAFE_ENABLED;
public static boolean PC_CAFE_ONLY_PREMIUM;
public static boolean PC_CAFE_ONLY_VIP;
public static int PC_CAFE_MAX_POINTS;
public static boolean PC_CAFE_ENABLE_DOUBLE_POINTS;
public static int PC_CAFE_DOUBLE_POINTS_CHANCE;
@@ -1242,6 +1245,13 @@ public class Config
public static boolean PC_CAFE_RANDOM_POINT;
public static boolean PC_CAFE_REWARD_LOW_EXP_KILLS;
public static int PC_CAFE_LOW_EXP_KILLS_CHANCE;
public static boolean VIP_SYSTEM_ENABLED;
public static boolean VIP_SYSTEM_PRIME_AFFECT;
public static int VIP_SYSTEM_MAX_TIER;
public static int VIP_SYSTEM_GOLD_DROP_MIN;
public static int VIP_SYSTEM_GOLD_DROP_MAX;
public static int VIP_SYSTEM_SILVER_DROP_MIN;
public static int VIP_SYSTEM_SILVER_DROP_MAX;
public static boolean SELLBUFF_ENABLED;
public static int SELLBUFF_MP_MULTIPLER;
public static int SELLBUFF_PAYMENT_ID;
@@ -1529,6 +1539,7 @@ public class Config
final PropertiesParser Attandance = new PropertiesParser(ATTENDANCE_CONFIG_FILE);
ENABLE_ATTENDANCE_REWARDS = Attandance.getBoolean("EnableAttendanceRewards", false);
PREMIUM_ONLY_ATTENDANCE_REWARDS = Attandance.getBoolean("PremiumOnlyAttendanceRewards", false);
VIP_ONLY_ATTENDANCE_REWARDS = Attandance.getBoolean("VipOnlyAttendanceRewards", false);
ATTENDANCE_REWARDS_SHARE_ACCOUNT = Attandance.getBoolean("AttendanceRewardsShareAccount", false);
ATTENDANCE_REWARD_DELAY = Attandance.getInt("AttendanceRewardDelay", 30);
ATTENDANCE_POPUP_START = Attandance.getBoolean("AttendancePopupStart", true);
@@ -3203,6 +3214,7 @@ public class Config
final PropertiesParser PcCafe = new PropertiesParser(CUSTOM_PC_CAFE_CONFIG_FILE);
PC_CAFE_ENABLED = PcCafe.getBoolean("PcCafeEnabled", false);
PC_CAFE_ONLY_PREMIUM = PcCafe.getBoolean("PcCafeOnlyPremium", false);
PC_CAFE_ONLY_VIP = PcCafe.getBoolean("PcCafeOnlyVip", false);
PC_CAFE_MAX_POINTS = PcCafe.getInt("MaxPcCafePoints", 200000);
if (PC_CAFE_MAX_POINTS < 0)
{
@@ -3231,6 +3243,22 @@ public class Config
PC_CAFE_LOW_EXP_KILLS_CHANCE = 100;
}
final PropertiesParser vipSystem = new PropertiesParser(CUSTOM_VIP_CONFIG_FILE);
VIP_SYSTEM_ENABLED = vipSystem.getBoolean("VipEnabled", false);
if (VIP_SYSTEM_ENABLED)
{
VIP_SYSTEM_PRIME_AFFECT = vipSystem.getBoolean("PrimeAffectPoints", false);
VIP_SYSTEM_MAX_TIER = vipSystem.getInt("MaxVipLevel", 7);
VIP_SYSTEM_SILVER_DROP_MIN = vipSystem.getInt("VipSilverDropMin", 1);
VIP_SYSTEM_SILVER_DROP_MAX = vipSystem.getInt("VipSilverDropMax", 5);
VIP_SYSTEM_GOLD_DROP_MIN = vipSystem.getInt("VipGoldenDropMin", 1);
VIP_SYSTEM_GOLD_DROP_MAX = vipSystem.getInt("VipGoldenDropMax", 5);
if (VIP_SYSTEM_MAX_TIER > 7)
{
VIP_SYSTEM_MAX_TIER = 7;
}
}
// Load PremiumSystem config file (if exists)
final PropertiesParser PremiumSystem = new PropertiesParser(CUSTOM_PREMIUM_SYSTEM_CONFIG_FILE);
PREMIUM_SYSTEM_ENABLED = PremiumSystem.getBoolean("EnablePremiumSystem", false);

View File

@@ -103,6 +103,7 @@ import org.l2jmobius.gameserver.data.xml.StaticObjectData;
import org.l2jmobius.gameserver.data.xml.TeleporterData;
import org.l2jmobius.gameserver.data.xml.TransformData;
import org.l2jmobius.gameserver.data.xml.VariationData;
import org.l2jmobius.gameserver.data.xml.VipData;
import org.l2jmobius.gameserver.geoengine.GeoEngine;
import org.l2jmobius.gameserver.handler.ConditionHandler;
import org.l2jmobius.gameserver.handler.DailyMissionHandler;
@@ -149,6 +150,7 @@ import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.olympiad.Hero;
import org.l2jmobius.gameserver.model.olympiad.Olympiad;
import org.l2jmobius.gameserver.model.vip.VipManager;
import org.l2jmobius.gameserver.model.votereward.VoteSystem;
import org.l2jmobius.gameserver.network.ClientNetworkManager;
import org.l2jmobius.gameserver.network.NpcStringId;
@@ -278,6 +280,7 @@ public class GameServer
CommissionManager.getInstance();
LuckyGameData.getInstance();
AttendanceRewardData.getInstance();
VipData.getInstance();
printSection("Characters");
ClassListData.getInstance();
@@ -295,6 +298,7 @@ public class GameServer
CharSummonTable.getInstance().init();
BeautyShopData.getInstance();
MentorManager.getInstance();
VipManager.getInstance();
if (Config.FACTION_SYSTEM_ENABLED)
{

View File

@@ -42,8 +42,10 @@ import org.l2jmobius.gameserver.network.serverpackets.primeshop.ExBRProductInfo;
public class PrimeShopData implements IXmlReader
{
private static final Logger LOGGER = Logger.getLogger(PrimeShopData.class.getName());
private static final int VIP_GIFT_INIT_ID = 100000;
private final Map<Integer, PrimeShopGroup> _primeItems = new LinkedHashMap<>();
private final Map<Integer, PrimeShopGroup> _vipGifts = new LinkedHashMap<>(10);
protected PrimeShopData()
{
@@ -109,8 +111,15 @@ public class PrimeShopData implements IXmlReader
items.add(new PrimeShopItem(itemId, count, item.getWeight(), item.isTradeable() ? 1 : 0));
}
}
_primeItems.put(set.getInt("id"), new PrimeShopGroup(set, items));
PrimeShopGroup group = new PrimeShopGroup(set, items);
if (group.isVipGift())
{
_vipGifts.put(set.getInt("id"), group);
}
else
{
_primeItems.put(set.getInt("id"), group);
}
}
}
}
@@ -131,7 +140,12 @@ public class PrimeShopData implements IXmlReader
public PrimeShopGroup getItem(int brId)
{
return _primeItems.get(brId);
PrimeShopGroup item = _primeItems.get(brId);
if (item == null)
{
item = _vipGifts.get(brId);
}
return item;
}
public Map<Integer, PrimeShopGroup> getPrimeItems()
@@ -148,4 +162,9 @@ public class PrimeShopData implements IXmlReader
{
protected static final PrimeShopData INSTANCE = new PrimeShopData();
}
public PrimeShopGroup getVipGiftOfTier(byte tier)
{
return _vipGifts.get(VIP_GIFT_INIT_ID + tier);
}
}

View File

@@ -0,0 +1,156 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.data.xml;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.l2jmobius.Config;
import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.gameserver.model.vip.VipInfo;
/**
* @author Gabriel Costa Souza
*/
public class VipData implements IXmlReader
{
private static final Logger LOGGER = Logger.getLogger(VipData.class.getName());
private final Map<Byte, VipInfo> _vipTiers = new HashMap<>();
protected VipData()
{
load();
}
@Override
public void load()
{
if (!Config.VIP_SYSTEM_ENABLED)
{
return;
}
_vipTiers.clear();
parseDatapackFile("data/vip.xml");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _vipTiers.size() + " vips.");
}
@Override
public void parseDocument(Document doc, File f)
{
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
VIP_FILE: for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("vip".equalsIgnoreCase(d.getNodeName()))
{
final NamedNodeMap attrs = d.getAttributes();
Node att;
byte tier = -1;
int required = -1;
int lose = -1;
att = attrs.getNamedItem("tier");
if (att == null)
{
LOGGER.severe(getClass().getSimpleName() + ": Missing tier for vip, skipping");
continue;
}
tier = Byte.parseByte(att.getNodeValue());
att = attrs.getNamedItem("points-required");
if (att == null)
{
LOGGER.severe(getClass().getSimpleName() + ": Missing points-required for vip: " + tier + ", skipping");
continue;
}
required = Integer.parseInt(att.getNodeValue());
att = attrs.getNamedItem("points-lose");
if (att == null)
{
LOGGER.severe(getClass().getSimpleName() + ": Missing points-lose for vip: " + tier + ", skipping");
continue;
}
lose = Integer.parseInt(att.getNodeValue());
final VipInfo vipInfo = new VipInfo(tier, required, lose);
for (Node c = d.getFirstChild(); c != null; c = c.getNextSibling())
{
if ("bonus".equalsIgnoreCase(c.getNodeName()))
{
final int skill = Integer.parseInt(c.getAttributes().getNamedItem("skill").getNodeValue());
final float silverChance = Float.parseFloat(c.getAttributes().getNamedItem("silverChance").getNodeValue());
final float goldChance = Float.parseFloat(c.getAttributes().getNamedItem("goldChance").getNodeValue());
try
{
vipInfo.setSkill(skill);
vipInfo.setSilverCoinChance(silverChance);
vipInfo.setGoldCoinChance(goldChance);
}
catch (Exception e)
{
LOGGER.severe(getClass().getSimpleName() + ": Error in bonus parameter for vip: " + tier + ", skipping");
continue VIP_FILE;
}
}
}
_vipTiers.put(tier, vipInfo);
}
}
}
}
}
/**
* Gets the single instance of VipData.
* @return single instance of VipData
*/
public static VipData getInstance()
{
return SingletonHolder.INSTANCE;
}
/**
* The Class SingletonHolder.
*/
private static class SingletonHolder
{
protected static final VipData INSTANCE = new VipData();
}
public int getSkillId(byte tier)
{
return _vipTiers.get(tier).getSkill();
}
public Map<Byte, VipInfo> getVipTiers()
{
return _vipTiers;
}
}

View File

@@ -39,7 +39,9 @@ import org.l2jmobius.gameserver.model.eventengine.ScheduleTarget;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.holders.SubClassHolder;
import org.l2jmobius.gameserver.model.olympiad.Olympiad;
import org.l2jmobius.gameserver.model.variables.AccountVariables;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.model.vip.VipManager;
import org.l2jmobius.gameserver.network.serverpackets.ExVoteSystemInfo;
import org.l2jmobius.gameserver.network.serverpackets.ExWorldChatCnt;
@@ -68,6 +70,7 @@ public class DailyTaskManager extends AbstractEventManager<AbstractEvent<?>>
resetRecommends();
resetWorldChatPoints();
resetTrainingCamp();
resetVip();
}
@ScheduleTarget
@@ -254,6 +257,24 @@ public class DailyTaskManager extends AbstractEventManager<AbstractEvent<?>>
}
}
private void resetVip()
{
// Delete all entries for received gifts
AccountVariables.deleteVipPurchases(AccountVariables.VIP_ITEM_BOUGHT);
// Checks the tier expiration for online players
// offline players get handled on next time they log in.
for (PlayerInstance player : World.getInstance().getPlayers())
{
if (player.getVipTier() > 0)
{
VipManager.getInstance().checkVipTierExpiration(player);
}
player.getAccountVariables().restoreMe();
}
}
private void resetDailyMissionRewards()
{
DailyMissionData.getInstance().getDailyMissionData().forEach(DailyMissionDataHolder::reset);

View File

@@ -39,6 +39,11 @@ public class PcCafePointsManager
return;
}
if (Config.PC_CAFE_ONLY_VIP && (player.getVipTier() <= 0))
{
return;
}
if (player.getPcCafePoints() >= Config.PC_CAFE_MAX_POINTS)
{
final SystemMessage message = new SystemMessage(SystemMessageId.YOU_HAVE_EARNED_THE_MAXIMUM_NUMBER_OF_PA_POINTS);

View File

@@ -21,6 +21,8 @@ import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -272,6 +274,7 @@ import org.l2jmobius.gameserver.model.stats.MoveType;
import org.l2jmobius.gameserver.model.stats.Stat;
import org.l2jmobius.gameserver.model.variables.AccountVariables;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.model.vip.VipManager;
import org.l2jmobius.gameserver.model.zone.ZoneId;
import org.l2jmobius.gameserver.model.zone.ZoneType;
import org.l2jmobius.gameserver.model.zone.type.WaterZone;
@@ -346,6 +349,7 @@ import org.l2jmobius.gameserver.network.serverpackets.UserInfo;
import org.l2jmobius.gameserver.network.serverpackets.ValidateLocation;
import org.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionInfo;
import org.l2jmobius.gameserver.network.serverpackets.friend.FriendStatus;
import org.l2jmobius.gameserver.network.serverpackets.vip.ReceiveVipInfo;
import org.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
import org.l2jmobius.gameserver.taskmanager.PlayerAutoSaveTaskManager;
import org.l2jmobius.gameserver.taskmanager.PvpFlagTaskManager;
@@ -404,7 +408,7 @@ public class PlayerInstance extends Playable
// Character Shortcut SQL String Definitions:
private static final String DELETE_CHAR_SHORTCUTS = "DELETE FROM character_shortcuts WHERE charId=? AND class_index=?";
// Character Recipe List Save:
// Character Recipe List Save
private static final String DELETE_CHAR_RECIPE_SHOP = "DELETE FROM character_recipeshoplist WHERE charId=?";
private static final String INSERT_CHAR_RECIPE_SHOP = "REPLACE INTO character_recipeshoplist (`charId`, `recipeId`, `price`, `index`) VALUES (?, ?, ?, ?)";
private static final String RESTORE_CHAR_RECIPE_SHOP = "SELECT * FROM character_recipeshoplist WHERE charId=? ORDER BY `index`";
@@ -855,6 +859,8 @@ public class PlayerInstance extends Playable
private ElementalSpirit[] _spirits;
private ElementalType _activeElementalSpiritType;
private byte _vipTier = 0;
private final List<QuestTimer> _questTimers = new ArrayList<>();
private final List<TimerHolder<?>> _timerHolders = new ArrayList<>();
@@ -2959,6 +2965,22 @@ public class PlayerInstance extends Playable
return _inventory.getAdena();
}
/**
* @return the Gold Coin amount of the PlayerInstance.
*/
public long getGoldCoin()
{
return _inventory.getGoldCoin();
}
/**
* @return the Silver Coin of the PlayerInstance.
*/
public long getSilverCoin()
{
return _inventory.getSilverCoin();
}
/**
* @return the Ancient Adena amount of the PlayerInstance.
*/
@@ -14018,6 +14040,57 @@ public class PlayerInstance extends Playable
}
}
public byte getVipTier()
{
return _vipTier;
}
public void setVipTier(byte vipTier)
{
_vipTier = vipTier;
}
public long getVipPoints()
{
return getAccountVariables().getLong(AccountVariables.VIP_POINTS, 0L);
}
public long getVipTierExpiration()
{
return getAccountVariables().getLong(AccountVariables.VIP_EXPIRATION, 0L);
}
public void setVipTierExpiration(long expiration)
{
getAccountVariables().set(AccountVariables.VIP_EXPIRATION, expiration);
}
public void updateVipPoints(long points)
{
if (points == 0)
{
return;
}
final int currentVipTier = VipManager.getInstance().getVipTier(getVipPoints());
getAccountVariables().set(AccountVariables.VIP_POINTS, getVipPoints() + points);
final byte newTier = VipManager.getInstance().getVipTier(getVipPoints());
if (newTier != currentVipTier)
{
_vipTier = newTier;
if (newTier > 0)
{
getAccountVariables().set(AccountVariables.VIP_EXPIRATION, Instant.now().plus(30, ChronoUnit.DAYS).toEpochMilli());
VipManager.getInstance().manageTier(this);
}
else
{
getAccountVariables().set(AccountVariables.VIP_EXPIRATION, 0L);
}
}
getAccountVariables().storeMe(); // force to store to prevent falty purchases after a crash.
sendPacket(new ReceiveVipInfo(this));
}
public void initElementalSpirits()
{
tryLoadSpirits();

View File

@@ -46,6 +46,7 @@ import org.l2jmobius.gameserver.model.itemcontainer.Inventory;
import org.l2jmobius.gameserver.model.items.Item;
import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.model.stats.Stat;
import org.l2jmobius.gameserver.model.vip.VipManager;
import org.l2jmobius.gameserver.util.Util;
/**
@@ -716,7 +717,6 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
}
final List<DropHolder> dropList = new ArrayList<>(getDropList(dropType));
// randomize drop order
Collections.shuffle(dropList);
@@ -733,15 +733,8 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
}
// check level gap that may prevent drop this item
final double levelGapChanceToDrop;
if (dropItem.getItemId() == Inventory.ADENA_ID)
{
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
}
else
{
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
}
final double levelGapChanceToDrop = calculateLevelGapChanceToDrop(dropItem, levelDifference);
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
{
continue;
@@ -789,9 +782,72 @@ public class NpcTemplate extends CreatureTemplate implements IIdentifiable
calculatedDrops.add(new ItemHolder(Config.CHAMPION_REWARD_ID, Config.CHAMPION_REWARD_QTY));
}
if (dropType == DropType.DROP)
{
processVipDrops(calculatedDrops, victim, killer);
}
return calculatedDrops;
}
private void processVipDrops(Collection<ItemHolder> items, Creature victim, Creature killer)
{
final List<DropHolder> dropList = new ArrayList<>();
if (killer.getActingPlayer() != null)
{
float silverCoinChance = VipManager.getInstance().getSilverCoinDropChance(killer.getActingPlayer());
float rustyCoinChance = VipManager.getInstance().getRustyCoinDropChance(killer.getActingPlayer());
if (silverCoinChance > 0)
{
dropList.add(new DropHolder(DropType.DROP, Inventory.SILVER_COIN, Config.VIP_SYSTEM_SILVER_DROP_MIN, Config.VIP_SYSTEM_SILVER_DROP_MAX, silverCoinChance));
}
if (rustyCoinChance > 0)
{
dropList.add(new DropHolder(DropType.DROP, Inventory.GOLD_COIN, Config.VIP_SYSTEM_GOLD_DROP_MIN, Config.VIP_SYSTEM_GOLD_DROP_MAX, rustyCoinChance));
}
}
for (DropHolder dropItem : dropList)
{
final ItemHolder drop = calculateDropWithLevelGap(dropItem, victim, killer);
if (drop == null)
{
continue;
}
items.add(drop);
}
}
private ItemHolder calculateDropWithLevelGap(DropHolder dropItem, Creature victim, Creature killer)
{
final int levelDifference = victim.getLevel() - killer.getLevel();
final double levelGapChanceToDrop = calculateLevelGapChanceToDrop(dropItem, levelDifference);
if ((Rnd.nextDouble() * 100) > levelGapChanceToDrop)
{
return null;
}
return calculateDrop(dropItem, victim, killer);
}
private double calculateLevelGapChanceToDrop(DropHolder dropItem, int levelDifference)
{
final double levelGapChanceToDrop;
if (dropItem.getItemId() == Inventory.ADENA_ID)
{
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ADENA_MAX_LEVEL_DIFFERENCE, -Config.DROP_ADENA_MIN_LEVEL_DIFFERENCE, Config.DROP_ADENA_MIN_LEVEL_GAP_CHANCE, 100.0);
}
else
{
levelGapChanceToDrop = Util.map(levelDifference, -Config.DROP_ITEM_MAX_LEVEL_DIFFERENCE, -Config.DROP_ITEM_MIN_LEVEL_DIFFERENCE, Config.DROP_ITEM_MIN_LEVEL_GAP_CHANCE, 100.0);
}
return levelGapChanceToDrop;
}
/**
* All item drop chance calculations are done by this method.
* @param dropItem

View File

@@ -90,6 +90,7 @@ import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerItemPi
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerItemTransfer;
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerItemUnequip;
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerLevelChanged;
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerLoad;
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerLogin;
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerLogout;
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerMenteeAdd;
@@ -259,6 +260,7 @@ public enum EventType
ON_PLAYER_LEVEL_CHANGED(OnPlayerLevelChanged.class, void.class),
ON_PLAYER_LOGIN(OnPlayerLogin.class, void.class),
ON_PLAYER_LOGOUT(OnPlayerLogout.class, void.class),
ON_PLAYER_LOAD(OnPlayerLoad.class, void.class),
ON_PLAYER_PK_CHANGED(OnPlayerPKChanged.class, void.class),
ON_PLAYER_PRESS_TUTORIAL_MARK(OnPlayerPressTutorialMark.class, void.class),
ON_PLAYER_MOVE_REQUEST(OnPlayerMoveRequest.class, void.class, TerminateReturn.class),

View File

@@ -0,0 +1,45 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.model.events.impl.creature.player;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.events.EventType;
import org.l2jmobius.gameserver.model.events.impl.IBaseEvent;
/**
* @author Gabriel Costa Souza
*/
public class OnPlayerLoad implements IBaseEvent
{
private final PlayerInstance _player;
public OnPlayerLoad(PlayerInstance player)
{
_player = player;
}
public PlayerInstance getPlayer()
{
return _player;
}
@Override
public EventType getType()
{
return EventType.ON_PLAYER_LOAD;
}
}

View File

@@ -83,6 +83,8 @@ public abstract class Inventory extends ItemContainer
// Common Items
public static final int ADENA_ID = 57;
public static final int SILVER_COIN = 29983;
public static final int GOLD_COIN = 29984;
public static final int ANCIENT_ADENA_ID = 5575;
public static final int BEAUTY_TICKET_ID = 36308;
public static final int AIR_STONE_ID = 39461;

View File

@@ -53,6 +53,8 @@ public class PlayerInventory extends Inventory
private final PlayerInstance _owner;
private ItemInstance _adena;
private ItemInstance _goldCoin;
private ItemInstance _silverCoin;
private ItemInstance _ancientAdena;
private ItemInstance _beautyTickets;
private Collection<Integer> _blockItems = null;
@@ -93,6 +95,16 @@ public class PlayerInventory extends Inventory
return _adena != null ? _adena.getCount() : 0;
}
public long getGoldCoin()
{
return _goldCoin != null ? _goldCoin.getCount() : 0;
}
public long getSilverCoin()
{
return _silverCoin != null ? _silverCoin.getCount() : 0;
}
public ItemInstance getAncientAdenaInstance()
{
return _ancientAdena;
@@ -403,6 +415,14 @@ public class PlayerInventory extends Inventory
{
_adena = addedItem;
}
else if ((addedItem.getId() == SILVER_COIN) && !addedItem.equals(_silverCoin))
{
_silverCoin = addedItem;
}
else if ((addedItem.getId() == GOLD_COIN) && !addedItem.equals(_goldCoin))
{
_goldCoin = addedItem;
}
else if ((addedItem.getId() == ANCIENT_ADENA_ID) && !addedItem.equals(_ancientAdena))
{
_ancientAdena = addedItem;
@@ -467,6 +487,14 @@ public class PlayerInventory extends Inventory
{
_adena = item;
}
else if ((item.getId() == SILVER_COIN) && !item.equals(_silverCoin))
{
_silverCoin = item;
}
else if ((item.getId() == GOLD_COIN) && !item.equals(_goldCoin))
{
_goldCoin = item;
}
else if ((item.getId() == ANCIENT_ADENA_ID) && !item.equals(_ancientAdena))
{
_ancientAdena = item;
@@ -515,6 +543,18 @@ public class PlayerInventory extends Inventory
{
final ItemInstance item = super.transferItem(process, objectId, count, target, actor, reference);
if ((_adena != null) && ((_adena.getCount() <= 0) || (_adena.getOwnerId() != getOwnerId())))
{
_adena = null;
}
if ((_silverCoin != null) && ((_silverCoin.getCount() <= 0) || (_silverCoin.getOwnerId() != getOwnerId())))
{
_silverCoin = null;
}
if ((_goldCoin != null) && ((_goldCoin.getCount() <= 0) || (_goldCoin.getOwnerId() != getOwnerId())))
{
_goldCoin = null;
}
if ((_adena != null) && ((_adena.getCount() <= 0) || (_adena.getOwnerId() != getOwnerId())))
{
_adena = null;
@@ -573,6 +613,14 @@ public class PlayerInventory extends Inventory
{
_adena = null;
}
if ((_silverCoin != null) && (_silverCoin.getCount() <= 0))
{
_silverCoin = null;
}
if ((_goldCoin != null) && (_goldCoin.getCount() <= 0))
{
_goldCoin = null;
}
if ((_ancientAdena != null) && (_ancientAdena.getCount() <= 0))
{
@@ -637,6 +685,14 @@ public class PlayerInventory extends Inventory
{
_adena = null;
}
if ((_silverCoin != null) && ((_silverCoin.getCount() <= 0) || (_silverCoin.getOwnerId() != getOwnerId())))
{
_silverCoin = null;
}
if ((_goldCoin != null) && ((_goldCoin.getCount() <= 0) || (_goldCoin.getOwnerId() != getOwnerId())))
{
_goldCoin = null;
}
if ((_ancientAdena != null) && ((_ancientAdena.getCount() <= 0) || (_ancientAdena.getOwnerId() != getOwnerId())))
{
@@ -671,6 +727,16 @@ public class PlayerInventory extends Inventory
_adena = null;
}
if ((_silverCoin != null) && ((_silverCoin.getCount() <= 0) || (_silverCoin.getOwnerId() != getOwnerId())))
{
_silverCoin = null;
}
if ((_goldCoin != null) && ((_goldCoin.getCount() <= 0) || (_goldCoin.getOwnerId() != getOwnerId())))
{
_goldCoin = null;
}
if ((_ancientAdena != null) && ((_ancientAdena.getCount() <= 0) || (_ancientAdena.getOwnerId() != getOwnerId())))
{
_ancientAdena = null;
@@ -720,6 +786,14 @@ public class PlayerInventory extends Inventory
{
_adena = null;
}
else if (item.getId() == SILVER_COIN)
{
_silverCoin = null;
}
else if (item.getId() == GOLD_COIN)
{
_goldCoin = null;
}
else if (item.getId() == ANCIENT_ADENA_ID)
{
_ancientAdena = null;
@@ -771,6 +845,8 @@ public class PlayerInventory extends Inventory
{
super.restore();
_adena = getItemByItemId(ADENA_ID);
_silverCoin = getItemByItemId(SILVER_COIN);
_goldCoin = getItemByItemId(GOLD_COIN);
_ancientAdena = getItemByItemId(ANCIENT_ADENA_ID);
_beautyTickets = getItemByItemId(BEAUTY_TICKET_ID);
}

View File

@@ -47,6 +47,9 @@ public class PrimeShopGroup
private final int _maxBirthday;
private final int _restrictionDay;
private final int _availableCount;
private final boolean _isVipGift;
private final int _vipTier;
private final int _silverCoin;
private final List<PrimeShopItem> _items;
public PrimeShopGroup(StatSet set, List<PrimeShopItem> items)
@@ -73,6 +76,10 @@ public class PrimeShopGroup
_maxBirthday = set.getInt("maxBirthday", 0);
_restrictionDay = set.getInt("restrictionDay", 0);
_availableCount = set.getInt("availableCount", 0);
_isVipGift = set.getBoolean("isVipGift", false);
_vipTier = set.getInt("vipTier", 0);
_silverCoin = set.getInt("silverCoin", 0);
_items = items;
}
@@ -196,8 +203,23 @@ public class PrimeShopGroup
return _availableCount;
}
public boolean isVipGift()
{
return _isVipGift;
}
public int getVipTier()
{
return _vipTier;
}
public List<PrimeShopItem> getItems()
{
return _items;
}
public int getSilverCoin()
{
return _silverCoin;
}
}

View File

@@ -37,10 +37,15 @@ public class AccountVariables extends AbstractVariables
private static final String SELECT_QUERY = "SELECT * FROM account_gsdata WHERE account_name = ?";
private static final String DELETE_QUERY = "DELETE FROM account_gsdata WHERE account_name = ?";
private static final String INSERT_QUERY = "INSERT INTO account_gsdata (account_name, var, value) VALUES (?, ?, ?)";
private static final String DELETE_QUERY_VAR = "DELETE FROM account_gsdata where var = ?";
// Public variable names
public static final String HWID = "HWID";
public static final String HWIDSLIT_VAR = " ";
public static final String VIP_POINTS = "VipPoints";
public static final String VIP_TIER = "VipTier";
public static final String VIP_EXPIRATION = "VipExpiration";
public static final String VIP_ITEM_BOUGHT = "Vip_Item_Bought";
private final String _accountName;
@@ -143,4 +148,28 @@ public class AccountVariables extends AbstractVariables
}
return true;
}
/**
* Delete all entries for an requested var
* @param var
* @return success
*/
public static boolean deleteVipPurchases(String var)
{
try (Connection con = DatabaseFactory.getConnection())
{
// Clear previous entries.
try (PreparedStatement st = con.prepareStatement(DELETE_QUERY_VAR))
{
st.setString(1, var);
st.execute();
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "AccountVariables: Couldn't delete vip variables!", e);
return false;
}
return true;
}
}

View File

@@ -0,0 +1,82 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.model.vip;
/**
* @author Gabriel Costa Souza
*/
public class VipInfo
{
private final byte _tier;
private final long _pointsRequired;
private final long _pointsDepreciated;
private float _silverCoinChance;
private float _goldCoinChance;
private int _skill;
public VipInfo(byte tier, long pointsRequired, long pointsDepreciated)
{
_tier = tier;
_pointsRequired = pointsRequired;
_pointsDepreciated = pointsDepreciated;
}
public byte getTier()
{
return _tier;
}
public long getPointsRequired()
{
return _pointsRequired;
}
public long getPointsDepreciated()
{
return _pointsDepreciated;
}
public int getSkill()
{
return _skill;
}
public void setSkill(int skill)
{
_skill = skill;
}
public void setSilverCoinChance(float silverCoinChance)
{
_silverCoinChance = silverCoinChance;
}
public float getSilverCoinChance()
{
return _silverCoinChance;
}
public void setGoldCoinChance(float goldCoinChance)
{
_goldCoinChance = goldCoinChance;
}
public float getGoldCoinChance()
{
return _goldCoinChance;
}
}

View File

@@ -0,0 +1,212 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.model.vip;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.function.Consumer;
import org.l2jmobius.Config;
import org.l2jmobius.gameserver.data.xml.SkillData;
import org.l2jmobius.gameserver.data.xml.VipData;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.events.Containers;
import org.l2jmobius.gameserver.model.events.EventType;
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerLoad;
import org.l2jmobius.gameserver.model.events.impl.creature.player.OnPlayerLogin;
import org.l2jmobius.gameserver.model.events.listeners.ConsumerEventListener;
import org.l2jmobius.gameserver.model.skills.Skill;
import org.l2jmobius.gameserver.model.variables.AccountVariables;
import org.l2jmobius.gameserver.network.serverpackets.ExBRNewIconCashBtnWnd;
import org.l2jmobius.gameserver.network.serverpackets.vip.ReceiveVipInfo;
/**
* @author Gabriel Costa Souza
*/
public final class VipManager
{
private static final byte VIP_MAX_TIER = (byte) Config.VIP_SYSTEM_MAX_TIER;
private final ConsumerEventListener _vipLoginListener = new ConsumerEventListener(null, EventType.ON_PLAYER_LOGIN, (Consumer<OnPlayerLogin>) this::onVipLogin, this);
private VipManager()
{
if (!Config.VIP_SYSTEM_ENABLED)
{
return;
}
Containers.Global().addListener(new ConsumerEventListener(Containers.Global(), EventType.ON_PLAYER_LOAD, (Consumer<OnPlayerLoad>) this::onPlayerLoaded, this));
}
private void onPlayerLoaded(OnPlayerLoad event)
{
final PlayerInstance player = event.getPlayer();
player.setVipTier(getVipTier(player));
if (player.getVipTier() > 0)
{
manageTier(player);
player.addListener(_vipLoginListener);
}
else
{
player.sendPacket(new ReceiveVipInfo(player));
player.sendPacket(new ExBRNewIconCashBtnWnd((byte) 0));
}
}
private boolean canReceiveGift(PlayerInstance player)
{
if (!Config.VIP_SYSTEM_ENABLED)
{
return false;
}
if (player.getVipTier() <= 0)
{
return false;
}
return player.getAccountVariables().getLong(AccountVariables.VIP_ITEM_BOUGHT, 0L) <= 0;
}
private void onVipLogin(OnPlayerLogin event)
{
final PlayerInstance player = event.getPlayer();
if (canReceiveGift(player))
{
player.sendPacket(new ExBRNewIconCashBtnWnd((byte) 1));
}
else
{
player.sendPacket(new ExBRNewIconCashBtnWnd((byte) 0));
}
player.removeListener(_vipLoginListener);
player.sendPacket(new ReceiveVipInfo(player));
}
public void manageTier(PlayerInstance player)
{
if (!checkVipTierExpiration(player))
{
player.sendPacket(new ReceiveVipInfo(player));
}
if (player.getVipTier() > 1)
{
final int oldSkillId = VipData.getInstance().getSkillId((byte) (player.getVipTier() - 1));
if (oldSkillId > 0)
{
final Skill oldSkill = SkillData.getInstance().getSkill(oldSkillId, 1);
if (oldSkill != null)
{
player.removeSkill(oldSkill);
}
}
}
final int skillId = VipData.getInstance().getSkillId(player.getVipTier());
if (skillId > 0)
{
final Skill skill = SkillData.getInstance().getSkill(skillId, 1);
if (skill != null)
{
player.addSkill(skill);
}
}
}
public byte getVipTier(PlayerInstance player)
{
return getVipInfo(player).getTier();
}
public byte getVipTier(long points)
{
byte temp = getVipInfo(points).getTier();
if (temp > VIP_MAX_TIER)
{
temp = VIP_MAX_TIER;
}
return temp;
}
private VipInfo getVipInfo(PlayerInstance player)
{
return getVipInfo(player.getVipPoints());
}
public float getSilverCoinDropChance(PlayerInstance player)
{
return getVipInfo(player).getSilverCoinChance();
}
public float getRustyCoinDropChance(PlayerInstance player)
{
return getVipInfo(player).getGoldCoinChance();
}
private VipInfo getVipInfo(long points)
{
for (byte i = 0; i < VipData.getInstance().getVipTiers().size(); i++)
{
if (points < VipData.getInstance().getVipTiers().get(i).getPointsRequired())
{
byte temp = (byte) (i - 1);
if (temp > VIP_MAX_TIER)
{
temp = VIP_MAX_TIER;
}
return VipData.getInstance().getVipTiers().get(temp);
}
}
return VipData.getInstance().getVipTiers().get(VIP_MAX_TIER);
}
public long getPointsDepreciatedOnLevel(byte vipTier)
{
return VipData.getInstance().getVipTiers().get(vipTier).getPointsDepreciated();
}
public long getPointsToLevel(byte level)
{
if (VipData.getInstance().getVipTiers().containsKey(level))
{
return VipData.getInstance().getVipTiers().get(level).getPointsRequired();
}
return 0;
}
public boolean checkVipTierExpiration(PlayerInstance player)
{
final Instant now = Instant.now();
if (now.isAfter(Instant.ofEpochMilli(player.getVipTierExpiration())))
{
player.updateVipPoints(-getPointsDepreciatedOnLevel(player.getVipTier()));
player.setVipTierExpiration(Instant.now().plus(30, ChronoUnit.DAYS).toEpochMilli());
return true;
}
return false;
}
public static VipManager getInstance()
{
return Singleton.INSTANCE;
}
private static class Singleton
{
private static final VipManager INSTANCE = new VipManager();
}
}

View File

@@ -98,6 +98,9 @@ import org.l2jmobius.gameserver.network.clientpackets.shuttle.MoveToLocationInSh
import org.l2jmobius.gameserver.network.clientpackets.shuttle.RequestShuttleGetOff;
import org.l2jmobius.gameserver.network.clientpackets.shuttle.RequestShuttleGetOn;
import org.l2jmobius.gameserver.network.clientpackets.training.NotifyTrainingRoomEnd;
import org.l2jmobius.gameserver.network.clientpackets.vip.ExRequestVipInfo;
import org.l2jmobius.gameserver.network.clientpackets.vip.RequestVipLuckGameInfo;
import org.l2jmobius.gameserver.network.clientpackets.vip.RequestVipProductList;
/**
* @author Sdw
@@ -361,11 +364,11 @@ public enum ExIncomingPackets implements IIncomingPackets<GameClient>
REQUEST_VIP_ATTENDANCE_CHECK(0x107, RequestVipAttendanceCheck::new, ConnectionState.IN_GAME),
REQUEST_ITEM_ENSOUL(0x108, RequestItemEnsoul::new, ConnectionState.IN_GAME),
REQUEST_CASTLE_WAR_SEASON_REWARD(0x109, null, ConnectionState.IN_GAME),
REQUEST_VIP_PRODUCT_LIST(0x10A, null, ConnectionState.IN_GAME),
REQUEST_VIP_LUCKY_GAME_INFO(0x10B, null, ConnectionState.IN_GAME),
REQUEST_VIP_PRODUCT_LIST(0x10A, RequestVipProductList::new, ConnectionState.IN_GAME),
REQUEST_VIP_LUCKY_GAME_INFO(0x10B, RequestVipLuckGameInfo::new, ConnectionState.IN_GAME),
REQUEST_VIP_LUCKY_GAME_ITEM_LIST(0x10C, null, ConnectionState.IN_GAME),
REQUEST_VIP_LUCKY_GAME_BONUS(0x10D, null, ConnectionState.IN_GAME),
EX_REQUEST_VIP_INFO(0x10E, null, ConnectionState.IN_GAME),
EX_REQUEST_VIP_INFO(0x10E, ExRequestVipInfo::new, ConnectionState.IN_GAME),
REQUEST_CAPTCHA_ANSWER(0x10F, null, ConnectionState.IN_GAME),
REQUEST_REFRESH_CAPTCHA_IMAGE(0x110, null, ConnectionState.IN_GAME),
REQUEST_PLEDGE_SIGN_IN_FOR_OPEN_JOINING_METHOD(0x111, RequestPledgeSignInForOpenJoiningMethod::new, ConnectionState.IN_GAME),

View File

@@ -61,6 +61,11 @@ public class RequestVipAttendanceCheck implements IClientIncomingPacket
player.sendPacket(SystemMessageId.YOUR_VIP_RANK_IS_TOO_LOW_TO_RECEIVE_THE_REWARD);
return;
}
else if (Config.VIP_ONLY_ATTENDANCE_REWARDS && (player.getVipTier() <= 0))
{
player.sendPacket(SystemMessageId.YOUR_VIP_RANK_IS_TOO_LOW_TO_RECEIVE_THE_REWARD);
return;
}
// Check login delay.
if (player.getUptime() < (Config.ATTENDANCE_REWARD_DELAY * 60 * 1000))

View File

@@ -17,6 +17,8 @@
package org.l2jmobius.gameserver.network.clientpackets.primeshop;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import org.l2jmobius.Config;
import org.l2jmobius.commons.network.PacketReader;
@@ -24,9 +26,11 @@ import org.l2jmobius.commons.util.Chronos;
import org.l2jmobius.gameserver.data.xml.PrimeShopData;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.actor.request.PrimeShopRequest;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.itemcontainer.Inventory;
import org.l2jmobius.gameserver.model.primeshop.PrimeShopGroup;
import org.l2jmobius.gameserver.model.primeshop.PrimeShopItem;
import org.l2jmobius.gameserver.model.variables.AccountVariables;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.primeshop.ExBRBuyProduct;
@@ -72,39 +76,68 @@ public class RequestBRBuyProduct implements IClientIncomingPacket
final PrimeShopGroup item = PrimeShopData.getInstance().getItem(_brId);
if (validatePlayer(item, _count, player))
{
final int price = (item.getPrice() * _count);
final int paymentId = validatePaymentId(item, price);
if (paymentId < 0)
boolean hasItems = true;
// First loop to validate all items
for (ItemHolder itemHolder : validatePaymentId(item))
{
final int paymentId = itemHolder.getId();
final long price = itemHolder.getCount() * _count;
if (paymentId < 0)
{
hasItems = false;
}
else if (paymentId > 0)
{
if (player.getInventory().getInventoryItemCount(paymentId, 0) < price)
{
hasItems = false;
}
}
else
{ // this is always 0
if (player.getPrimePoints() < price)
{
hasItems = false;
}
}
}
if (!hasItems)
{
player.sendPacket(new ExBRBuyProduct(ExBrProductReplyType.LACK_OF_POINT));
player.removeRequest(PrimeShopRequest.class);
return;
}
else if (paymentId > 0)
// Second loop, only if all criteria has been met!
// this should always be reached if player has all the coins needed for the purchase
for (ItemHolder itemHolder : validatePaymentId(item))
{
if (!player.destroyItemByItemId("PrimeShop-" + item.getBrId(), paymentId, price, player, true))
final int paymentId = itemHolder.getId();
final long price = itemHolder.getCount() * _count;
if (paymentId > 0)
{
player.sendPacket(new ExBRBuyProduct(ExBrProductReplyType.LACK_OF_POINT));
player.removeRequest(PrimeShopRequest.class);
return;
player.destroyItemByItemId("PrimeShop-" + item.getBrId(), paymentId, price, player, true);
}
}
else if (paymentId == 0)
{
if (player.getPrimePoints() < price)
else if (paymentId == 0)
{
player.sendPacket(new ExBRBuyProduct(ExBrProductReplyType.LACK_OF_POINT));
player.removeRequest(PrimeShopRequest.class);
return;
player.setPrimePoints(player.getPrimePoints() - (int) price);
if (Config.VIP_SYSTEM_PRIME_AFFECT)
{
player.updateVipPoints(price);
}
}
player.setPrimePoints(player.getPrimePoints() - price);
}
for (PrimeShopItem subItem : item.getItems())
{
player.addItem("PrimeShop", subItem.getId(), subItem.getCount() * _count, player, true);
}
if (item.isVipGift())
{
player.getAccountVariables().set(AccountVariables.VIP_ITEM_BOUGHT, Calendar.getInstance().getTimeInMillis());
}
player.sendPacket(new ExBRBuyProduct(ExBrProductReplyType.SUCCESS));
player.sendPacket(new ExBRGamePoint(player));
}
@@ -169,6 +202,12 @@ public class RequestBRBuyProduct implements IClientIncomingPacket
return false;
}
if ((item.getVipTier() > player.getVipTier()) || (item.isVipGift() && !canReceiveGift(player, item)))
{
player.sendPacket(new ExBRBuyProduct(ExBrProductReplyType.SOLD_OUT));
return false;
}
final int weight = item.getWeight() * count;
final long slots = item.getCount() * count;
if (player.getInventory().validateWeight(weight))
@@ -188,23 +227,71 @@ public class RequestBRBuyProduct implements IClientIncomingPacket
return true;
}
private static int validatePaymentId(PrimeShopGroup item, long amount)
/**
* Check if player can receive Gift from L2 Store
* @param player player in question
* @param item requested item.
* @return true if player can receive gift item.
*/
private static boolean canReceiveGift(PlayerInstance player, PrimeShopGroup item)
{
if (!Config.VIP_SYSTEM_ENABLED)
{
return false;
}
if (player.getVipTier() <= 0)
{
return false;
}
else if (item.getVipTier() != player.getVipTier())
{
player.sendMessage("This item is not for your vip tier!");
return false;
}
else
{
long timeBought = player.getAccountVariables().getLong(AccountVariables.VIP_ITEM_BOUGHT, 0L);
return timeBought <= 0;
}
}
private static List<ItemHolder> validatePaymentId(PrimeShopGroup item)
{
List<ItemHolder> temp = new LinkedList<>();
switch (item.getPaymentType())
{
case 0: // Prime points
{
return 0;
if (item.getVipTier() > 0)
{
if (item.getPrice() > 0)
{
temp.add(new ItemHolder(Inventory.GOLD_COIN, item.getPrice()));
}
if (item.getSilverCoin() > 0)
{
temp.add(new ItemHolder(Inventory.SILVER_COIN, item.getSilverCoin()));
}
}
else
{
temp.add(new ItemHolder(0, item.getPrice())); // prime points
}
return temp;
}
case 1: // Adenas
{
return Inventory.ADENA_ID;
temp.add(new ItemHolder(Inventory.ADENA_ID, item.getPrice())); // Is this even used????
return temp;
}
case 2: // Hero coins
{
return HERO_COINS;
temp.add(new ItemHolder(HERO_COINS, item.getPrice())); // Is this even used????
return temp;
}
}
return -1;
temp.add(new ItemHolder(-1, -1));
return temp;
}
}

View File

@@ -88,6 +88,13 @@ public class RequestBRPresentBuyProduct implements IClientIncomingPacket
player.addRequest(new PrimeShopRequest(player));
final PrimeShopGroup item = PrimeShopData.getInstance().getItem(_brId);
if (item.isVipGift())
{
player.sendMessage("You cannot gift a Vip Gift!");
return;
}
if (validatePlayer(item, _count, player))
{
final int price = (item.getPrice() * _count);
@@ -116,6 +123,10 @@ public class RequestBRPresentBuyProduct implements IClientIncomingPacket
return;
}
player.setPrimePoints(player.getPrimePoints() - price);
if (Config.VIP_SYSTEM_PRIME_AFFECT)
{
player.updateVipPoints(price);
}
}
player.sendPacket(new ExBRBuyProduct(ExBrProductReplyType.SUCCESS));

View File

@@ -0,0 +1,37 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.clientpackets.vip;
import org.l2jmobius.commons.network.PacketReader;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.vip.ReceiveVipInfo;
public class ExRequestVipInfo implements IClientIncomingPacket
{
@Override
public boolean read(GameClient client, PacketReader packet)
{
return true;
}
@Override
public void run(GameClient client)
{
client.sendPacket(new ReceiveVipInfo(client.getPlayer()));
}
}

View File

@@ -0,0 +1,37 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.clientpackets.vip;
import org.l2jmobius.commons.network.PacketReader;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.vip.ReceiveVipLuckyGameInfo;
public class RequestVipLuckGameInfo implements IClientIncomingPacket
{
@Override
public boolean read(GameClient client, PacketReader packet)
{
return true;
}
@Override
public void run(GameClient client)
{
client.sendPacket(new ReceiveVipLuckyGameInfo(client.getPlayer()));
}
}

View File

@@ -0,0 +1,37 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.clientpackets.vip;
import org.l2jmobius.commons.network.PacketReader;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.vip.ReceiveVipProductList;
public class RequestVipProductList implements IClientIncomingPacket
{
@Override
public boolean read(GameClient client, PacketReader packet)
{
return true;
}
@Override
public void run(GameClient client)
{
client.sendPacket(new ReceiveVipProductList(client.getPlayer()));
}
}

View File

@@ -0,0 +1,41 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.serverpackets;
import org.l2jmobius.commons.network.PacketWriter;
import org.l2jmobius.gameserver.network.OutgoingPackets;
/**
* @author Gabriel Costa Souza
*/
public class ExBRNewIconCashBtnWnd implements IClientOutgoingPacket
{
private final short _active;
public ExBRNewIconCashBtnWnd(short active)
{
_active = active;
}
@Override
public boolean write(PacketWriter packet)
{
OutgoingPackets.EX_BR_NEW_ICON_CASH_BTN_WND.writeId(packet);
packet.writeH(_active);
return true;
}
}

View File

@@ -38,7 +38,7 @@ public class ExBrPremiumState implements IClientOutgoingPacket
OutgoingPackets.EX_BR_PREMIUM_STATE.writeId(packet);
packet.writeD(_player.getObjectId());
packet.writeC(_player.hasPremiumStatus() ? 0x01 : 0x00);
packet.writeC(_player.hasPremiumStatus() || (_player.getVipTier() > 0) ? 0x01 : 0x00);
return true;
}
}

View File

@@ -30,7 +30,7 @@ public class ExWorldChatCnt implements IClientOutgoingPacket
public ExWorldChatCnt(PlayerInstance player)
{
_points = player.getLevel() < Config.WORLD_CHAT_MIN_LEVEL ? 0 : Math.max(player.getWorldChatPoints() - player.getWorldChatUsed(), 0);
_points = (player.getLevel() < Config.WORLD_CHAT_MIN_LEVEL) || (player.getVipTier() <= 0) ? 0 : Math.max(player.getWorldChatPoints() - player.getWorldChatUsed(), 0);
}
@Override

View File

@@ -0,0 +1,60 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.serverpackets.vip;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import org.l2jmobius.Config;
import org.l2jmobius.commons.network.PacketWriter;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.vip.VipManager;
import org.l2jmobius.gameserver.network.OutgoingPackets;
import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
public class ReceiveVipInfo implements IClientOutgoingPacket
{
private final PlayerInstance _player;
public ReceiveVipInfo(PlayerInstance player)
{
_player = player;
}
@Override
public boolean write(PacketWriter packet)
{
if (!Config.VIP_SYSTEM_ENABLED)
{
return false;
}
final VipManager vipManager = VipManager.getInstance();
final byte vipTier = _player.getVipTier();
final int vipDuration = (int) ChronoUnit.SECONDS.between(Instant.now(), Instant.ofEpochMilli(_player.getVipTierExpiration()));
OutgoingPackets.RECIVE_VIP_INFO.writeId(packet);
packet.writeC(vipTier);
packet.writeQ(_player.getVipPoints());
packet.writeD(vipDuration);
packet.writeQ(vipManager.getPointsToLevel((byte) (vipTier + 1)));
packet.writeQ(vipManager.getPointsDepreciatedOnLevel(vipTier));
packet.writeC(vipTier);
packet.writeQ(vipManager.getPointsToLevel(vipTier));
return true;
}
}

View File

@@ -0,0 +1,48 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.serverpackets.vip;
import org.l2jmobius.commons.network.PacketWriter;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.items.instance.ItemInstance;
import org.l2jmobius.gameserver.network.OutgoingPackets;
import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
/**
* @author Gabriel Costa Souza
*/
public class ReceiveVipLuckyGameInfo implements IClientOutgoingPacket
{
private final PlayerInstance _player;
private final static int LCOIN_ID = 91663; // FIXME: Does not exist in client.
public ReceiveVipLuckyGameInfo(PlayerInstance player)
{
_player = player;
}
@Override
public boolean write(PacketWriter packet)
{
OutgoingPackets.RECIVE_VIP_LUCKY_GAME_INFO.writeId(packet);
packet.writeC(1); // enabled
packet.writeH((int) _player.getAdena());
ItemInstance item = _player.getInventory().getItemByItemId(LCOIN_ID);
packet.writeH(item == null ? 0 : (int) item.getCount()); // L Coin count
return true;
}
}

View File

@@ -0,0 +1,90 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.serverpackets.vip;
import java.util.Collection;
import org.l2jmobius.Config;
import org.l2jmobius.commons.network.PacketWriter;
import org.l2jmobius.gameserver.data.xml.PrimeShopData;
import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance;
import org.l2jmobius.gameserver.model.primeshop.PrimeShopGroup;
import org.l2jmobius.gameserver.model.primeshop.PrimeShopItem;
import org.l2jmobius.gameserver.network.OutgoingPackets;
import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
public class ReceiveVipProductList implements IClientOutgoingPacket
{
private final PlayerInstance _player;
public ReceiveVipProductList(PlayerInstance player)
{
_player = player;
}
@Override
public boolean write(PacketWriter packet)
{
if (!Config.VIP_SYSTEM_ENABLED)
{
return false;
}
final Collection<PrimeShopGroup> products = PrimeShopData.getInstance().getPrimeItems().values();
final PrimeShopGroup gift = PrimeShopData.getInstance().getVipGiftOfTier(_player.getVipTier());
OutgoingPackets.RECIVE_VIP_PRODUCT_LIST.writeId(packet);
packet.writeQ(_player.getAdena());
packet.writeQ(_player.getGoldCoin()); // Gold Coin Amount
packet.writeQ(_player.getSilverCoin()); // Silver Coin Amount
packet.writeC(1); // Show Reward tab
if (gift != null)
{
packet.writeD(products.size() + 1);
writeProduct(gift, packet);
}
else
{
packet.writeD(products.size());
}
for (PrimeShopGroup product : products)
{
writeProduct(product, packet);
}
return true;
}
private void writeProduct(PrimeShopGroup product, PacketWriter buffer)
{
buffer.writeD(product.getBrId());
buffer.writeC(product.getCat());
buffer.writeC(product.getPaymentType());
buffer.writeD(product.getPrice()); // L2 Coin | Gold Coin seems to use the same field based on payment type
buffer.writeD(product.getSilverCoin());
buffer.writeC(product.getPanelType()); // NEW - 6; HOT - 5 ... Unk
buffer.writeC(product.getVipTier());
buffer.writeC(10);
buffer.writeC(product.getItems().size());
for (PrimeShopItem item : product.getItems())
{
buffer.writeD(item.getId());
buffer.writeD((int) item.getCount());
}
}
}