Support for Balthus Event.

Contributed by Index.
This commit is contained in:
MobiusDevelopment 2022-03-23 11:23:11 +00:00
parent 7e327f1402
commit 5dd8637495
81 changed files with 3714 additions and 36 deletions

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/multisell.xsd">
<npcs>
<npc>34330</npc> <!-- Festival Fairy -->
</npcs>
<item>
<ingredient id="49783" count="70" /> <!-- Fairy's Lucky Coin -->
<ingredient id="57" count="100000" /> <!-- Adena -->
<production id="81707" count="1" /> <!-- Festival Fairy's Gift - Event -->
</item>
<item>
<ingredient id="49783" count="8" /> <!-- Fairy's Lucky Coin -->
<ingredient id="57" count="500000" /> <!-- Adena -->
<production id="80934" count="1" /> <!-- Festival Fairy's Box: Crystals - Event -->
</item>
<item>
<ingredient id="49783" count="20" /> <!-- Fairy's Lucky Coin -->
<production id="48229" count="1" /> <!-- Party Summoning Scroll -->
</item>
<item>
<ingredient id="49783" count="25" /> <!-- Fairy's Lucky Coin -->
<production id="13302" count="1" /> <!-- My Teleport Scroll - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81869" count="1" /> <!-- Superior Ruby Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81870" count="1" /> <!-- Superior Sapphire Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81871" count="1" /> <!-- Superior Red Cat's Eye Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81872" count="1" /> <!-- Superior Blue Cat's Eye Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80472" count="1" /> <!-- Greater Topaz Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80475" count="1" /> <!-- Greater Obsidian Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80476" count="1" /> <!-- Greater Opal Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80477" count="1" /> <!-- Greater Emerald Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80478" count="1" /> <!-- Greater Aquamarine Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80479" count="1" /> <!-- Greater Diamond Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80480" count="1" /> <!-- Greater Pearl Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80481" count="1" /> <!-- Greater Vital Stone Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80482" count="1" /> <!-- Greater Garnet Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="200" /> <!-- Fairy's Lucky Coin -->
<production id="80483" count="1" /> <!-- Greater Tanzanite Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="500" /> <!-- Fairy's Lucky Coin -->
<production id="80484" count="1" /> <!-- Greater Red Cat's Eye Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="500" /> <!-- Fairy's Lucky Coin -->
<production id="80485" count="1" /> <!-- Greater Blue Cat's Eye Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80486" count="1" /> <!-- Mysterious Talisman - STR - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80487" count="1" /> <!-- Mysterious Talisman - INT - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80488" count="1" /> <!-- Mysterious Talisman - DEX - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80489" count="1" /> <!-- Mysterious Talisman - WIT - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80490" count="1" /> <!-- Mysterious Talisman - CON - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80491" count="1" /> <!-- Mysterious Talisman - MEN - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80492" count="1" /> <!-- Mysterious Talisman - Attribute Attack - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80493" count="1" /> <!-- Mysterious Talisman - Attribute Resistance - 7-day -->
</item>
</list>

View File

@ -0,0 +1,6 @@
<html><body>Event Manager Festival Fairy:<br>
Every hour I was trying raffle the item of all the player.<br>
For start to be participant - you need to get coupon and use it.<br>
Every day you can get 3 coupons from the Bag and I can sell you more coupons.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,5 @@
<html><body>Event Manager Festival Fairy:<br>
Here we go.<br>
I give you this bag, but on event period you can get only one!<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,4 @@
<html><body>Event Manager Festival Fairy:<br>
Sorry, but you already have your Event Bag.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,6 @@
<html><body>Event Manager Festival Fairy:<br>
I can exchange coupons for you, let me see on your coupon.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival exchange_coupon_1">+6 Leviathan Robe</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival exchange_coupon_2">+6 Leviathan Light Armor</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival exchange_coupon_3">+6 Leviathan Heavy Armor</Button>
</body></html>

View File

@ -0,0 +1,4 @@
<html><body>Event Manager Festival Fairy:<br>
Sorry, but you don't have required coupon.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,4 @@
<html><body>Event Manager Festival Fairy:<br>
Good luck in next raffle!<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,5 @@
<html><body>Event Manager Festival Fairy:<br>
I cant give you Bags with Coupons, because you level is too small!<br>
Back to me, when your level will be %require_level%<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,10 @@
<html><body>Event Manager Festival Fairy:<br>
Hello! Are you want to win some reward today?<br>
Don't worry, I will give for all player's consolation reward if someone won reward!<br>
If you have some Fairy Coins - I can exchange it on items for you.<br>
Good luck!<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330-1.htm">Learn more about the event</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 343300001">Exchange coins on items</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330-4.htm">I want to exchange reward coupon</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival get_event_bag">Give me Event Bag for taking Coupons</Button>
</body></html>

View File

@ -0,0 +1,236 @@
/*
* 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 events.BalthusFestival;
import java.util.ArrayList;
import java.util.List;
import org.l2jmobius.gameserver.instancemanager.events.BalthusEventManager;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.events.EventType;
import org.l2jmobius.gameserver.model.events.ListenerRegisterType;
import org.l2jmobius.gameserver.model.events.annotations.RegisterEvent;
import org.l2jmobius.gameserver.model.events.annotations.RegisterType;
import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSkillFinishCast;
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.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.quest.LongTimeEvent;
import org.l2jmobius.gameserver.model.skill.BuffInfo;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEvent;
/**
* @author Index
*/
public class BalthusFestival extends LongTimeEvent
{
// NPC
private static final int FESTIVAL_FAIRY = 34330;
// Item
private static final ItemHolder GOOD_LUCK_BAG = new ItemHolder(60011, 1); // Festival Fairy's Good Luck Bag
// Skills
private static final List<SkillHolder> SKILLS = new ArrayList<>(8);
static
{
SKILLS.add(new SkillHolder(29441, 1)); // Fairy_Coupon_1_Hour
SKILLS.add(new SkillHolder(39171, 1)); // Fairy_Coupon_2_Hour
SKILLS.add(new SkillHolder(39171, 2)); // Fairy_Coupon_3_Hour
SKILLS.add(new SkillHolder(39171, 3)); // Fairy_Coupon_6_Hour
SKILLS.add(new SkillHolder(39171, 4)); // Fairy_Coupon_8_Hour
SKILLS.add(new SkillHolder(39171, 5)); // Fairy_Coupon_Unlimited_Hour
SKILLS.add(new SkillHolder(27859, 1)); // Balthus_Coupon_2_Hour
SKILLS.add(new SkillHolder(48853, 1)); // Balthus_Coupon_2_Hour
}
// Misc
private static final String BALTHUS_BAG_VAR = "BALTHUS_BAG";
private BalthusFestival()
{
addStartNpc(FESTIVAL_FAIRY);
addFirstTalkId(FESTIVAL_FAIRY);
addTalkId(FESTIVAL_FAIRY);
if (isEventPeriod())
{
BalthusEventManager.getInstance();
}
}
@RegisterEvent(EventType.ON_PLAYER_LOGIN)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void onPlayerLogin(OnPlayerLogin event)
{
if (!isEventPeriod())
{
return;
}
final Player player = event.getPlayer();
if (player == null)
{
return;
}
for (SkillHolder skill : SKILLS)
{
final BuffInfo buff = player.getEffectList().getBuffInfoBySkillId(skill.getSkillId());
if (buff != null)
{
cancelQuestTimer("balthusEventBuff" + player.getObjectId(), null, player);
startQuestTimer("balthusEventBuff" + player.getObjectId(), buff.getTime() * 1000, null, player);
BalthusEventManager.getInstance().addPlayer(player);
}
}
player.sendPacket(new ExBalthusEvent(player));
}
@RegisterEvent(EventType.ON_PLAYER_LOGOUT)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void onPlayerLogout(OnPlayerLogout event)
{
if (!isEventPeriod())
{
return;
}
final Player player = event.getPlayer();
if ((player == null))
{
return;
}
cancelQuestTimer("balthusEventBuff" + player.getObjectId(), null, player);
BalthusEventManager.getInstance().removePlayer(player);
}
@RegisterEvent(EventType.ON_CREATURE_SKILL_FINISH_CAST)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void onCreatureSkillFinishCast(OnCreatureSkillFinishCast event)
{
if (!isEventPeriod())
{
return;
}
final Player player = event.getCaster().getActingPlayer();
if (player == null)
{
return;
}
for (SkillHolder skill : SKILLS)
{
if (event.getSkill() == skill.getSkill())
{
startQuestTimer("balthusEventBuff" + player.getObjectId(), skill.getSkill().getAbnormalTime() * 1000, null, player);
BalthusEventManager.getInstance().addPlayer(player);
player.sendPacket(new ExBalthusEvent(player));
}
}
}
@Override
public String onAdvEvent(String event, Npc npc, Player player)
{
if (!isEventPeriod())
{
return "Balthus Event disabled.";
}
if (event.equals("balthusEventBuff" + player.getObjectId()))
{
BalthusEventManager.getInstance().removePlayer(player);
player.sendPacket(new ExBalthusEvent(player));
}
if (event.equals("get_event_bag"))
{
if (player.getLevel() < BalthusEventManager.getInstance().getMinimalLevel())
{
return getHtm(player, "34300-7.htm").replace("%require_level%", String.valueOf(BalthusEventManager.getInstance().getMinimalLevel()));
}
else if (player.getVariables().getBoolean(BALTHUS_BAG_VAR, false))
{
return "34330-3.htm";
}
else
{
player.getVariables().set(BALTHUS_BAG_VAR, true);
player.addItem("Balthus Event", GOOD_LUCK_BAG.getId(), GOOD_LUCK_BAG.getCount(), null, true);
return "34330-2.htm";
}
}
else if (event.equals("34330.htm"))
{
return event;
}
else if (event.equals("34330-1.htm"))
{
return event;
}
else if (event.equals("34330-4.htm"))
{
return event;
}
else if (event.startsWith("exchange_coupon_"))
{
switch (event.substring(16))
{
case ("1"):
{
if (!player.destroyItemByItemId("Destroy Coupon", 81726, 1, null, true))
{
return "34330-5.htm";
}
player.addItem("Balthus Coupon", 81711, 1, null, true);
return "34330-6.htm";
}
case ("2"):
{
if (!player.destroyItemByItemId("Destroy Coupon", 81726, 1, null, true))
{
return "34330-5.htm";
}
player.addItem("Balthus Coupon", 81710, 1, null, true);
return "34330-6.htm";
}
case ("3"):
{
if (!player.destroyItemByItemId("Destroy Coupon", 81726, 1, null, true))
{
return "34330-5.htm";
}
player.addItem("Balthus Coupon", 81709, 1, null, true);
return "34330-6.htm";
}
}
}
return null;
}
@Override
public String onFirstTalk(Npc npc, Player player)
{
return npc.getId() + ".htm";
}
public static void main(String[] args)
{
new BalthusFestival();
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<event name="Balthus Event" active="30 06 2021-29 07 2021" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/eventConfig.xsd">
<!-- Reward sets on reward.xml -->
<spawnlist>
<add npc="34330" x="-14143" y="123176" z="-3096" heading="30212" /> <!-- Gludio -->
<add npc="34330" x="16354" y="142848" z="-2680" heading="14450" /> <!-- Dion -->
<add npc="34330" x="80814" y="147987" z="-3448" heading="3355" /> <!-- Giran -->
<add npc="34330" x="82008" y="53874" z="-1472" heading="3355" /> <!-- Oren -->
<add npc="34330" x="147457" y="27863" z="-2248" heading="17863" /> <!-- Aden -->
<add npc="34330" x="112172" y="220447" z="-3648" heading="30708" /> <!-- Heine -->
<add npc="34330" x="148195" y="-57368" z="-2752" heading="17863" /> <!-- Goddard -->
<add npc="34330" x="44530" y="-48368" z="-776" heading="14450" /> <!-- Rune -->
<add npc="34330" x="86897" y="-141346" z="-1320" heading="49153" /> <!-- Shutgard -->
<add npc="34330" x="-114822" y="256385" z="-1472" heading="49744" /> <!-- Talking Island -->
<add npc="34330" x="-78832" y="249115" z="-3272" heading="56380" /> <!-- Faeron Village -->
<add npc="34330" x="-80485" y="149537" z="-3016" heading="16383" /> <!-- Gluddin -->
<add npc="34330" x="117380" y="76684" z="-2672" heading="40961" /> <!-- Hunters Village -->
<add npc="34330" x="208499" y="87743" z="-1006" heading="11264" /> <!-- Arcan -->
</spawnlist>
<messages>
<add type="onEnd" text="Balthus Festival: Event end!" />
<add type="onEnter" text="Balthus Festival: Event ongoing!" />
</messages>
</event>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
https://l2central.info/main/events_and_promos/848.html?lang=en
https://l2central.info/main/events_and_promos/608.html?lang=ru
https://eu.4gameforum.com/threads/661220/
reward from - hour - to - hour
item id - item_id - count - item_count - chance - chance for been chosen like reward - chance_to_win - chance for item for been raffled;
-->
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="rewards.xsd" easyMode="true" minLevel="105" id="49783" count="100" mailSubject="Balthus Knight Lottery" mailContent="You win reward in Balthus Event!">
<reward from="11" to="19">
<items>
<item id="81453" count="1" chance="50" lotteryChance="12.5"/>
<item id="48910" count="1" chance="50" lotteryChance="12.5"/>
<item id="81832" count="1" chance="50" lotteryChance="12.5"/>
<item id="48677" count="1" chance="50" lotteryChance="12.5"/>
<item id="48678" count="1" chance="50" lotteryChance="12.5"/>
<item id="81726" count="1" chance="50" lotteryChance="12.5"/>
<item id="80501" count="1" chance="50" lotteryChance="12.5"/>
<item id="81429" count="1" chance="50" lotteryChance="12.5"/>
</items>
</reward>
<reward from="20" to="22">
<items>
<item id="35564" count="1" chance="50" lotteryChance="33"/>
<item id="29385" count="1" chance="50" lotteryChance="33"/>
<item id="19464" count="1" chance="50" lotteryChance="34"/>
</items>
</reward>
<reward from="23" to="23">
<items>
<item id="36414" count="1" chance="50" lotteryChance="100"/>
</items>
</reward>
<reward from="00" to="10">
<items>
<item id="47399" count="1" chance="50" lotteryChance="100"/>
</items>
</reward>
</list>

View File

@ -0,0 +1,41 @@
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="list">
<xs:complexType>
<xs:sequence>
<xs:element name="reward" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element name="item" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="id" use="optional"/>
<xs:attribute type="xs:int" name="count" use="optional"/>
<xs:attribute type="xs:double" name="chance" use="optional"/>
<xs:attribute type="xs:double" name="lotteryChance" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:int" name="from" use="optional"/>
<xs:attribute type="xs:int" name="to" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="easyMode"/>
<xs:attribute type="xs:int" name="minLevel"/>
<xs:attribute type="xs:int" name="id"/>
<xs:attribute type="xs:int" name="count"/>
<xs:attribute type="xs:string" name="mailSubject"/>
<xs:attribute type="xs:string" name="mailContent"/>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -102,12 +102,16 @@
<!-- Disguises you as a Balthus Knight for 2 h. Can be used only by characters of level 85 or higher. The effect is removed if you switch to a different class. -->
<set name="icon" val="icon.ev_balthus_token" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="reuse_delay" val="120000" /> <!-- 1 minute -->
<set name="material" val="PAPER" />
<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_freightable" val="true" />
<set name="handler" val="ItemSkills" />
<skills>
<skill id="27859" level="1" /> <!-- Lucky Gift Coupon (2-hour) -->
</skills>
</item>
<item id="28610" name="Veteran Duo Bracelet Pack" additionalName="Event" type="EtcItem">
<!-- Contains 1 Veteran Duo Bracelet. -->

View File

@ -1285,12 +1285,16 @@
<!-- Can apply to the Lucky Gift raffle for 2 h. Can be used only by characters of level 85 or higher. The effect is removed if you switch to a different class. -->
<set name="icon" val="icon.ev_balthus_token" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="reuse_delay" val="120000" /> <!-- 1 minute -->
<set name="material" val="PAPER" />
<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_freightable" val="true" />
<set name="material" val="PAPER" />
<set name="handler" val="ItemSkills" />
<skills>
<skill id="39171" level="1" /> <!-- Lucky Gift Coupon (2-hour) -->
</skills>
</item>
<item id="47386" name="Sibi's Letter" additionalName="Event" type="EtcItem">
<!-- Letter from Sibi, the Balthus Knights Supply Officer. -->

View File

@ -402,6 +402,14 @@
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="39171" level="2" /> <!--Lucky Gift Coupon (3-hour) -->
</skills>
</item>
<item id="48224" name="Lucky Gift Coupon" additionalName="6-hour" type="EtcItem">
<!-- For 6 h., changes the appearance of your armor into that of the Hanbok, also allows you to take part in the Lucky Gift Draw. For characters of level 85 or higher. The effect is removed if you switch to a different class. -->
@ -413,6 +421,14 @@
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="39171" level="3" /> <!--Lucky Gift Coupon (6-hour) -->
</skills>
</item>
<item id="48225" name="Festival Fairy's Five-colored Sweets" additionalName="Event" type="EtcItem">
<!-- For 30 min., Vitality bonus +30%. -->

View File

@ -740,6 +740,14 @@
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="39171" level="4" /> <!--Lucky Gift Coupon (8-hour) -->
</skills>
</item>
<item id="48854" name="1 Billion Adena Box" type="EtcItem">
<!-- Festival Fairy's gift. Double-click to obtain 1 billion adena. -->

View File

@ -86,6 +86,17 @@
<set name="is_dropable" val="false" />
<set name="is_sellable" val="false" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="reuse_delay" val="5" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="29441" level="1" /> <!-- Glowing Dragon's Attribute Potion -->
</skills>
</item>
<item id="60010" name="Pantheon's Protection Box" type="EtcItem">
<!-- Double-click to obtain 1 useful item with a certain chance. -->
@ -98,12 +109,19 @@
<item id="60011" name="Festival Fairy's Good Luck Bag" additionalName="Event" type="EtcItem">
<!-- Double-click to obtain 3 Festival Fairy's Lucky Tickets (1-hour). -->
<set name="icon" val="icon.card_event_luck_pocket" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="material" val="FISH" />
<set name="is_tradable" val="false" />
<set name="is_dropable" val="false" />
<set name="is_destroyable" val="false" />
<set name="is_sellable" val="false" />
<set name="default_action" val="PEEL" />
<set name="immediate_effect" val="true" />
<set name="material" val="PAPER" />
<set name="is_stackable" val="true" />
<set name="reuse_delay" val="86400000" /> <!-- 1 Day -->
<set name="handler" val="ExtractableItems" />
<capsuled_items>
<item id="60009" min="3" max="3" chance="100" /> <!-- Festival Fairy's Lucky Ticket -->
</capsuled_items>
</item>
<item id="60012" name="Barter Package" type="EtcItem">
<!-- Double-click to obtain rare items. -->

View File

@ -1103,8 +1103,41 @@
<skill id="27859" toLevel="1" name="Balthus Knights' Top-grade Mark">
<!-- Grants you a disguise for 2 h. You'll have a chance to receive special supplies. Acquired XP/ SP +50%. -->
<icon>icon.ev_balthus_token</icon>
<operateType>A1</operateType>
<itemConsumeCount>1</itemConsumeCount>
<itemConsumeId>28609</itemConsumeId>
<abnormalLevel>1</abnormalLevel>
<abnormalTime>7200</abnormalTime>
<abnormalType>CHANGEBODY</abnormalType>
<abnormalVisualEffect>CHANGESHAPE_TRANSFORM</abnormalVisualEffect>
<stayAfterDeath>true</stayAfterDeath>
<blockedInOlympiad>true</blockedInOlympiad>
<effectPoint>1</effectPoint>
<isMagic>4</isMagic> <!-- Magic Skill -->
<magicLevel>56</magicLevel>
<operateType>A2</operateType>
<reuseDelay>60000</reuseDelay>
<canBeDispelled>false</canBeDispelled>
<hitTime>500</hitTime>
<basicProperty>NONE</basicProperty>
<magicCriticalRate>5</magicCriticalRate>
<hitCancelTime>0</hitCancelTime>
<targetType>SELF</targetType>
<affectScope>SINGLE</affectScope>
<irreplacableBuff>true</irreplacableBuff>
<isNecessaryToggle>true</isNecessaryToggle>
<passiveConditions>
<condition name="CheckLevel">
<minLevel>85</minLevel>
</condition>
</passiveConditions>
<effects>
<effect name="ExpModify">
<amount>50</amount>
</effect>
<effect name="SpModify">
<amount>50</amount>
</effect>
</effects>
</skill>
<skill id="27860" toLevel="1" name="Royal R99-grade White Save Ticket - Armor">
<operateType>A1</operateType>

View File

@ -1969,7 +1969,74 @@
<skill id="29441" toLevel="1" name="Lucky Gift Coupon (1-hour)">
<!-- For $s1, PvE damage +10%, Attribute Resistance +20, acquired XP +10%. Allows to take part in the raffle. -->
<icon>icon.skill0000</icon>
<operateType>A1</operateType>
<itemConsumeCount>1</itemConsumeCount>
<itemConsumeId>60009</itemConsumeId>
<abnormalLevel>1</abnormalLevel>
<abnormalTime>3600</abnormalTime>
<abnormalType>CHANGEBODY</abnormalType>
<abnormalVisualEffect>CHANGESHAPE_TRANSFORM</abnormalVisualEffect>
<stayAfterDeath>true</stayAfterDeath>
<blockedInOlympiad>true</blockedInOlympiad>
<effectPoint>1</effectPoint>
<isMagic>4</isMagic> <!-- Magic Skill -->
<magicLevel>56</magicLevel>
<operateType>A2</operateType>
<reuseDelay>60000</reuseDelay>
<canBeDispelled>false</canBeDispelled>
<hitTime>500</hitTime>
<basicProperty>NONE</basicProperty>
<magicCriticalRate>5</magicCriticalRate>
<hitCancelTime>0</hitCancelTime>
<targetType>SELF</targetType>
<affectScope>SINGLE</affectScope>
<irreplacableBuff>true</irreplacableBuff>
<isNecessaryToggle>true</isNecessaryToggle>
<passiveConditions>
<condition name="CheckLevel">
<minLevel>85</minLevel>
</condition>
</passiveConditions>
<effects>
<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="DefenceAttribute">
<amount>20</amount>
<attribute>FIRE</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>WATER</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>EARTH</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>WIND</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>HOLY</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>DARK</attribute>
</effect>
<effect name="ExpModify">
<amount>10</amount>
</effect>
</effects>
</skill>
<skill id="29442" toLevel="1" name="Freya's Lucky Pouch">
<icon>icon.skill0000</icon>

View File

@ -47,10 +47,18 @@
<value level="4">icon.etc_lottery_card_i00</value>
<value level="5">icon.christmas_card_box2</value>
</icon>
<itemConsumeCount>1</itemConsumeCount>
<itemConsumeId>49784</itemConsumeId>
<abnormalLevel>1</abnormalLevel>
<abnormalTime>3600</abnormalTime>
<abnormalLevel>
<value level="1">1</value>
<value level="2">2</value>
<value level="3">3</value>
<value level="4">4</value>
</abnormalLevel>
<abnormalTime>
<value level="1">3600</value>
<value level="2">7200</value>
<value level="3">21600</value>
<value level="4">28800</value>
</abnormalTime>
<abnormalType>CHANGEBODY</abnormalType>
<abnormalVisualEffect>CHANGESHAPE_TRANSFORM</abnormalVisualEffect>
<stayAfterDeath>true</stayAfterDeath>
@ -67,6 +75,8 @@
<hitCancelTime>0</hitCancelTime>
<targetType>SELF</targetType>
<affectScope>SINGLE</affectScope>
<isNecessaryToggle>true</isNecessaryToggle>
<irreplacableBuff>true</irreplacableBuff>
<passiveConditions>
<condition name="CheckLevel">
<minLevel>85</minLevel>

View File

@ -0,0 +1,407 @@
/*
* 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.instancemanager.events;
import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.l2jmobius.commons.threads.ThreadPool;
import org.l2jmobius.commons.util.Chronos;
import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.commons.util.Rnd;
import org.l2jmobius.gameserver.enums.MailType;
import org.l2jmobius.gameserver.instancemanager.MailManager;
import org.l2jmobius.gameserver.model.Message;
import org.l2jmobius.gameserver.model.StatSet;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.item.instance.Item;
import org.l2jmobius.gameserver.model.itemcontainer.Mail;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEvent;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEventJackpotUser;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Index
*/
public class BalthusEventManager implements IXmlReader
{
protected static final Logger LOGGER = Logger.getLogger(BalthusEventManager.class.getName());
private final Set<Player> _players = ConcurrentHashMap.newKeySet();
private final Map<Integer, BalthusEventHolder> _templates = new HashMap<>();
private boolean _isEasyMode;
private ItemHolder _consolation;
private int _minimalLevel = 0;
private String _mailSubject = null;
private String _mailContent = null;
private boolean _isRunning = false;
private int _currProgress;
private int _currState;
private int _avoidMinutesIssue;
private Player _winner = null;
private ItemChanceHolder _rewardItem;
public void addPlayer(Player player)
{
_players.add(player);
}
public void removePlayer(Player player)
{
_players.remove(player);
}
public Set<Player> getPlayers()
{
return _players;
}
public void removeParticipant(Player player)
{
_players.remove(player);
}
public boolean isPlayerParticipant(Player player)
{
return _players.contains(player);
}
public int getMinimalLevel()
{
return _minimalLevel;
}
public int getCurrentProgress()
{
return _currProgress;
}
public int getCurrentState()
{
return _currState;
}
public ItemHolder getConsolation()
{
return _consolation;
}
public int getCurrRewardItem()
{
return _rewardItem.getId();
}
public boolean isRunning()
{
return _isRunning;
}
public int getTime()
{
return Calendar.getInstance().get(Calendar.MINUTE) * 60; // client makes 3600 - time
}
protected BalthusEventManager()
{
load();
final long currentTime = Chronos.currentTimeMillis();
final Calendar calendar = Calendar.getInstance();
final long hours = calendar.get(Calendar.HOUR_OF_DAY);
final long mins = calendar.get(Calendar.MINUTE);
long startDelay;
if (mins <= 11)
{
calendar.set(Calendar.MINUTE, 12);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 20;
_avoidMinutesIssue = 1;
}
else if (mins <= 23)
{
calendar.set(Calendar.MINUTE, 24);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 40;
_avoidMinutesIssue = 2;
}
else if (mins <= 35)
{
calendar.set(Calendar.MINUTE, 36);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 60;
_avoidMinutesIssue = 3;
}
else if (mins <= 47)
{
calendar.set(Calendar.MINUTE, 48);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 80;
_avoidMinutesIssue = 4;
}
else
{
calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + 1);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 100;
_avoidMinutesIssue = 5;
}
if (((hours > 11) && (hours < 23)) || (hours == 23))
{
_currState = (int) hours - 11;
}
else
{
_currState = (int) hours + 13;
}
getNewRewardItem();
ThreadPool.scheduleAtFixedRate(this::tryToGetWinner, startDelay, 720000);
}
@Override
public synchronized void load()
{
_templates.clear();
parseDatapackFile("data/scripts/events/BalthusFestival/rewards.xml");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _templates.size() + " rewards.");
}
@Override
public void parseDocument(Document doc, File f)
{
final AtomicInteger i = new AtomicInteger();
forEach(doc, "list", listNode ->
{
final StatSet set = new StatSet(parseAttributes(listNode));
if (_minimalLevel == 0)
{
_isEasyMode = set.getBoolean("easyMode", false);
_minimalLevel = set.getInt("minLevel", 85);
_consolation = new ItemHolder(set.getInt("id", 49783), set.getInt("count", 100));
_mailSubject = set.getString("mailSubject", "Balthus Knight Lottery");
_mailContent = set.getString("mailContent", "You win reward in Balthus Event!");
}
forEach(listNode, "reward", reward ->
{
final AtomicInteger j = new AtomicInteger();
final Map<Integer, Map<ItemChanceHolder, Double>> tempRewardList = new HashMap<>();
final Map<Integer, Integer> rewardTime = new HashMap<>();
final StatSet rewardSet = new StatSet(parseAttributes(reward));
rewardTime.put(rewardSet.getInt("from"), rewardSet.getInt("to", rewardSet.getInt("from")));
forEach(reward, "items", itemNode ->
{
forEach(itemNode, "item", item ->
{
final Map<ItemChanceHolder, Double> tempChanceRewardList = new HashMap<>();
j.getAndIncrement();
final StatSet itemSet = new StatSet(parseAttributes(item));
ItemChanceHolder itemChanceHolder = new ItemChanceHolder(itemSet.getInt("id", 57), itemSet.getDouble("chance", 100), itemSet.getInt("count", 100));
tempChanceRewardList.put(itemChanceHolder, itemSet.getDouble("lotteryChance", 0.0));
tempRewardList.put(j.intValue(), tempChanceRewardList);
});
i.getAndIncrement();
_templates.put(i.intValue(), new BalthusEventHolder(rewardTime, tempRewardList));
});
});
});
}
private void tryToGetWinner()
{
_avoidMinutesIssue++;
if (_isRunning && (_avoidMinutesIssue != 6))
{
return;
}
final int random = Rnd.get(100);
if (!_isRunning && (random >= _rewardItem.getChance()) && !_players.isEmpty())
{
final List<Player> playerList = new ArrayList<>(_players);
Collections.shuffle(playerList);
for (Player player : playerList)
{
if (player.getLevel() >= getMinimalLevel())
{
_winner = player;
}
}
if (_winner != null)
{
LOGGER.info(getClass().getSimpleName() + ": New winner for " + _currState + " of Balthus Event is " + _winner.getName() + " - " + _winner.getObjectId() + ". Player win " + new Item(_rewardItem.getId()).getItemName() + " - " + _rewardItem.getId() + " count: " + _rewardItem.getCount() + ".");
Broadcast.toAllOnlinePlayers(new ExBalthusEventJackpotUser());
Broadcast.toAllOnlinePlayers(new SystemMessage(SystemMessageId.S1_HAS_OBTAINED_S2_FROM_THE_FESTIVAL_FAIRY).addPcName(_winner).addItemName(_rewardItem.getId()));
_isRunning = true;
sendConsolationItemsToAll();
sendRewardToPlayer(_winner);
}
else
{
_currProgress += 20;
}
}
else
{
_currProgress += 20;
}
if (_avoidMinutesIssue == 6)
{
resetCurrentStage();
}
for (Player player : World.getInstance().getPlayers())
{
player.sendPacket(new ExBalthusEvent(player));
}
}
private void resetCurrentStage()
{
_currState += 1;
_winner = null;
if (_currState == 25)
{
_currState = 1;
}
_currProgress = 20;
if (!_isRunning && _isEasyMode)
{
sendConsolationItemsToAll();
}
_isRunning = false;
_rewardItem = null;
_avoidMinutesIssue = 1;
getNewRewardItem();
}
private void sendConsolationItemsToAll()
{
for (Player player : _players)
{
if (player == _winner)
{
continue;
}
player.getVariables().set(PlayerVariables.BALTHUS_REWARD, player.getVariables().getInt(PlayerVariables.BALTHUS_REWARD, 0) + _consolation.getCount());
player.sendPacket(new SystemMessage(SystemMessageId.YOU_VE_OBTAINED_S1_LUCKY_COINS).addInt((int) _consolation.getCount()));
}
}
private void getNewRewardItem()
{
while (_rewardItem == null)
{
for (BalthusEventHolder holder : _templates.values())
{
if (holder.getRewardTime() == null)
{
continue;
}
final Map<Integer, Integer> rewardTime = holder.getRewardTime();
final int firstParam = rewardTime.keySet().iterator().hasNext() ? rewardTime.keySet().iterator().next() : 0;
final Calendar calendar = Calendar.getInstance();
if ((firstParam <= calendar.get(Calendar.HOUR_OF_DAY)) && (calendar.get(Calendar.HOUR_OF_DAY) <= rewardTime.get(firstParam)))
{
final double random = Rnd.get(100d);
double chance = 0;
for (Map<ItemChanceHolder, Double> map : holder.getRewardList().values())
{
for (Entry<ItemChanceHolder, Double> entry : map.entrySet())
{
chance += entry.getValue();
if (chance >= random)
{
_rewardItem = entry.getKey();
LOGGER.info(getClass().getSimpleName() + ": Reward for " + _currState + " stage set. Next reward item is " + new Item(_rewardItem.getId()).getItemName() + " - " + _rewardItem.getId() + " count: " + _rewardItem.getCount() + ".");
break;
}
}
if (_rewardItem != null)
{
break;
}
}
}
}
}
}
private void sendRewardToPlayer(Player player)
{
final Message msg = new Message(player.getObjectId(), _mailSubject, _mailContent, MailType.NEWS_INFORMER);
final Mail attachments = msg.createAttachments();
attachments.addItem("Balthus Knight Lottery", _rewardItem.getId(), _rewardItem.getCount(), null, null);
MailManager.getInstance().sendMessage(msg);
}
public static class BalthusEventHolder
{
// From hour to hour.
private final Map<Integer, Integer> _rewardTime;
// Time reward - Reward item, chance to put in lottery.
private final Map<Integer, Map<ItemChanceHolder, Double>> _rewardList;
public BalthusEventHolder(Map<Integer, Integer> rewardTime, Map<Integer, Map<ItemChanceHolder, Double>> rewardList)
{
_rewardTime = rewardTime;
_rewardList = rewardList;
}
public Map<Integer, Integer> getRewardTime()
{
return _rewardTime;
}
public Map<Integer, Map<ItemChanceHolder, Double>> getRewardList()
{
return _rewardList;
}
}
public static BalthusEventManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final BalthusEventManager INSTANCE = new BalthusEventManager();
}
}

View File

@ -63,6 +63,7 @@ public class PlayerVariables extends AbstractVariables
public static final String CLAN_CONTRIBUTION = "CLAN_CONTRIBUTION";
public static final String CLAN_CONTRIBUTION_TOTAL = "CLAN_CONTRIBUTION_TOTAL";
public static final String CLAN_CONTRIBUTION_REWARDED = "CLAN_CONTRIBUTION_REWARDED";
public static final String BALTHUS_REWARD = "BALTHUS_REWARD";
public static final String AUTO_USE_SETTINGS = "AUTO_USE_SETTINGS";
public static final String AUTO_USE_SHORTCUTS = "AUTO_USE_SHORTCUTS";
public static final String HUNTING_ZONE_ENTRY = "HUNTING_ZONE_ENTRY_";

View File

@ -48,6 +48,7 @@ import org.l2jmobius.gameserver.network.clientpackets.attributechange.SendChange
import org.l2jmobius.gameserver.network.clientpackets.autoplay.ExAutoPlaySetting;
import org.l2jmobius.gameserver.network.clientpackets.autoplay.ExRequestActivateAutoShortcut;
import org.l2jmobius.gameserver.network.clientpackets.awakening.RequestCallToChangeClass;
import org.l2jmobius.gameserver.network.clientpackets.balthusevent.RequestEventBalthusToken;
import org.l2jmobius.gameserver.network.clientpackets.ceremonyofchaos.RequestCancelCuriousHouse;
import org.l2jmobius.gameserver.network.clientpackets.ceremonyofchaos.RequestCuriousHouseHtml;
import org.l2jmobius.gameserver.network.clientpackets.ceremonyofchaos.RequestJoinCuriousHouse;
@ -435,7 +436,7 @@ public enum ExIncomingPackets implements IIncomingPackets<GameClient>
REQUEST_CHECK_AGIT_DECO_AVAILABILITY(0x117, null, ConnectionState.IN_GAME),
REQUEST_USER_FACTION_INFO(0x118, RequestUserFactionInfo::new, ConnectionState.IN_GAME),
EX_EXIT_ARENA(0x119, null, ConnectionState.IN_GAME),
REQUEST_EVENT_BALTHUS_TOKEN(0x11A, null, ConnectionState.IN_GAME),
REQUEST_EVENT_BALTHUS_TOKEN(0x11A, RequestEventBalthusToken::new, ConnectionState.IN_GAME),
REQUEST_PARTY_MATCHING_HISTORY(0x11B, null, ConnectionState.IN_GAME),
EX_ARENA_CUSTOM_NOTIFICATION(0x11C, null, ConnectionState.IN_GAME),
REQUEST_TODO_LIST(0x11D, null, ConnectionState.IN_GAME),

View File

@ -0,0 +1,63 @@
/*
* 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.balthusevent;
import org.l2jmobius.commons.network.PacketReader;
import org.l2jmobius.gameserver.instancemanager.events.BalthusEventManager;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEvent;
/**
* @author Index
*/
public class RequestEventBalthusToken implements IClientIncomingPacket
{
@Override
public boolean read(GameClient client, PacketReader packet)
{
return true;
}
@Override
public void run(GameClient client)
{
final Player player = client.getPlayer();
if (player == null)
{
return;
}
final int count = player.getVariables().getInt(PlayerVariables.BALTHUS_REWARD, 0);
if (count != 0)
{
if (player.addItem("Balthus Consolation Item", BalthusEventManager.getInstance().getConsolation().getId(), count, player, true) != null)
{
player.getVariables().set(PlayerVariables.BALTHUS_REWARD, 0);
player.sendPacket(new ExBalthusEvent(player));
}
}
else
{
player.sendPacket(new SystemMessage(SystemMessageId.YOU_VE_OBTAINED_S1_LUCKY_COINS));
}
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.balthusevent;
import org.l2jmobius.commons.network.PacketWriter;
import org.l2jmobius.gameserver.instancemanager.events.BalthusEventManager;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.network.OutgoingPackets;
import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
/**
* Consolation prize changing in SysTextures/ui6.ugx file "RewardClip.as" -> configUI -> this.tokenItemID = 49783;
* @author Index
*/
public class ExBalthusEvent implements IClientOutgoingPacket
{
private final Player _player;
public ExBalthusEvent(Player player)
{
_player = player;
}
@Override
public boolean write(PacketWriter packet)
{
OutgoingPackets.EX_BALTHUS_EVENT.writeId(packet);
packet.writeD(BalthusEventManager.getInstance().getCurrentState()); // CurrentState (max 24, because 1 state going 1 hour)
packet.writeD(BalthusEventManager.getInstance().getCurrentProgress()); // Progress
packet.writeD(BalthusEventManager.getInstance().getCurrRewardItem()); // CurrentRewardItem (current event item, what can be rewarded)
packet.writeD(_player.getVariables().getInt(PlayerVariables.BALTHUS_REWARD, 0)); // RewardTokenCount (current items for withdraw (available rewards))
packet.writeD((int) BalthusEventManager.getInstance().getConsolation().getCount()); // CurrentTokenCount (current count of "consolation prize")
packet.writeD(BalthusEventManager.getInstance().isPlayerParticipant(_player) ? 1 : 0); // Participated (player in event?)
packet.writeC(BalthusEventManager.getInstance().isRunning() ? 0 : 1); // Running (0 - already someone get this reward ? / 1 - item can be rewarded)
packet.writeD(BalthusEventManager.getInstance().getTime()); // Time (in seconds)
return true;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.balthusevent;
import org.l2jmobius.commons.network.PacketWriter;
import org.l2jmobius.gameserver.network.OutgoingPackets;
import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
/**
* @author Index
*/
public class ExBalthusEventJackpotUser implements IClientOutgoingPacket
{
public static final ExBalthusEventJackpotUser STATIC_PACKET = new ExBalthusEventJackpotUser();
@Override
public boolean write(PacketWriter packet)
{
OutgoingPackets.EX_BALTHUS_EVENT_JACKPOT_USER.writeId(packet);
return true;
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/multisell.xsd">
<npcs>
<npc>34330</npc> <!-- Festival Fairy -->
</npcs>
<item>
<ingredient id="49783" count="70" /> <!-- Fairy's Lucky Coin -->
<ingredient id="57" count="100000" /> <!-- Adena -->
<production id="81707" count="1" /> <!-- Festival Fairy's Gift - Event -->
</item>
<item>
<ingredient id="49783" count="8" /> <!-- Fairy's Lucky Coin -->
<ingredient id="57" count="500000" /> <!-- Adena -->
<production id="80934" count="1" /> <!-- Festival Fairy's Box: Crystals - Event -->
</item>
<item>
<ingredient id="49783" count="20" /> <!-- Fairy's Lucky Coin -->
<production id="48229" count="1" /> <!-- Party Summoning Scroll -->
</item>
<item>
<ingredient id="49783" count="25" /> <!-- Fairy's Lucky Coin -->
<production id="13302" count="1" /> <!-- My Teleport Scroll - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81869" count="1" /> <!-- Superior Ruby Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81870" count="1" /> <!-- Superior Sapphire Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81871" count="1" /> <!-- Superior Red Cat's Eye Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81872" count="1" /> <!-- Superior Blue Cat's Eye Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80472" count="1" /> <!-- Greater Topaz Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80475" count="1" /> <!-- Greater Obsidian Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80476" count="1" /> <!-- Greater Opal Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80477" count="1" /> <!-- Greater Emerald Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80478" count="1" /> <!-- Greater Aquamarine Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80479" count="1" /> <!-- Greater Diamond Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80480" count="1" /> <!-- Greater Pearl Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80481" count="1" /> <!-- Greater Vital Stone Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80482" count="1" /> <!-- Greater Garnet Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="200" /> <!-- Fairy's Lucky Coin -->
<production id="80483" count="1" /> <!-- Greater Tanzanite Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="500" /> <!-- Fairy's Lucky Coin -->
<production id="80484" count="1" /> <!-- Greater Red Cat's Eye Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="500" /> <!-- Fairy's Lucky Coin -->
<production id="80485" count="1" /> <!-- Greater Blue Cat's Eye Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80486" count="1" /> <!-- Mysterious Talisman - STR - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80487" count="1" /> <!-- Mysterious Talisman - INT - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80488" count="1" /> <!-- Mysterious Talisman - DEX - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80489" count="1" /> <!-- Mysterious Talisman - WIT - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80490" count="1" /> <!-- Mysterious Talisman - CON - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80491" count="1" /> <!-- Mysterious Talisman - MEN - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80492" count="1" /> <!-- Mysterious Talisman - Attribute Attack - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80493" count="1" /> <!-- Mysterious Talisman - Attribute Resistance - 7-day -->
</item>
</list>

View File

@ -0,0 +1,6 @@
<html><body>Event Manager Festival Fairy:<br>
Every hour I was trying raffle the item of all the player.<br>
For start to be participant - you need to get coupon and use it.<br>
Every day you can get 3 coupons from the Bag and I can sell you more coupons.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,5 @@
<html><body>Event Manager Festival Fairy:<br>
Here we go.<br>
I give you this bag, but on event period you can get only one!<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,4 @@
<html><body>Event Manager Festival Fairy:<br>
Sorry, but you already have your Event Bag.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,6 @@
<html><body>Event Manager Festival Fairy:<br>
I can exchange coupons for you, let me see on your coupon.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival exchange_coupon_1">+6 Leviathan Robe</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival exchange_coupon_2">+6 Leviathan Light Armor</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival exchange_coupon_3">+6 Leviathan Heavy Armor</Button>
</body></html>

View File

@ -0,0 +1,4 @@
<html><body>Event Manager Festival Fairy:<br>
Sorry, but you don't have required coupon.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,4 @@
<html><body>Event Manager Festival Fairy:<br>
Good luck in next raffle!<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,5 @@
<html><body>Event Manager Festival Fairy:<br>
I cant give you Bags with Coupons, because you level is too small!<br>
Back to me, when your level will be %require_level%<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,10 @@
<html><body>Event Manager Festival Fairy:<br>
Hello! Are you want to win some reward today?<br>
Don't worry, I will give for all player's consolation reward if someone won reward!<br>
If you have some Fairy Coins - I can exchange it on items for you.<br>
Good luck!<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330-1.htm">Learn more about the event</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 343300001">Exchange coins on items</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330-4.htm">I want to exchange reward coupon</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival get_event_bag">Give me Event Bag for taking Coupons</Button>
</body></html>

View File

@ -0,0 +1,236 @@
/*
* 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 events.BalthusFestival;
import java.util.ArrayList;
import java.util.List;
import org.l2jmobius.gameserver.instancemanager.events.BalthusEventManager;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.events.EventType;
import org.l2jmobius.gameserver.model.events.ListenerRegisterType;
import org.l2jmobius.gameserver.model.events.annotations.RegisterEvent;
import org.l2jmobius.gameserver.model.events.annotations.RegisterType;
import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSkillFinishCast;
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.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.quest.LongTimeEvent;
import org.l2jmobius.gameserver.model.skill.BuffInfo;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEvent;
/**
* @author Index
*/
public class BalthusFestival extends LongTimeEvent
{
// NPC
private static final int FESTIVAL_FAIRY = 34330;
// Item
private static final ItemHolder GOOD_LUCK_BAG = new ItemHolder(60011, 1); // Festival Fairy's Good Luck Bag
// Skills
private static final List<SkillHolder> SKILLS = new ArrayList<>(8);
static
{
SKILLS.add(new SkillHolder(29441, 1)); // Fairy_Coupon_1_Hour
SKILLS.add(new SkillHolder(39171, 1)); // Fairy_Coupon_2_Hour
SKILLS.add(new SkillHolder(39171, 2)); // Fairy_Coupon_3_Hour
SKILLS.add(new SkillHolder(39171, 3)); // Fairy_Coupon_6_Hour
SKILLS.add(new SkillHolder(39171, 4)); // Fairy_Coupon_8_Hour
SKILLS.add(new SkillHolder(39171, 5)); // Fairy_Coupon_Unlimited_Hour
SKILLS.add(new SkillHolder(27859, 1)); // Balthus_Coupon_2_Hour
SKILLS.add(new SkillHolder(48853, 1)); // Balthus_Coupon_2_Hour
}
// Misc
private static final String BALTHUS_BAG_VAR = "BALTHUS_BAG";
private BalthusFestival()
{
addStartNpc(FESTIVAL_FAIRY);
addFirstTalkId(FESTIVAL_FAIRY);
addTalkId(FESTIVAL_FAIRY);
if (isEventPeriod())
{
BalthusEventManager.getInstance();
}
}
@RegisterEvent(EventType.ON_PLAYER_LOGIN)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void onPlayerLogin(OnPlayerLogin event)
{
if (!isEventPeriod())
{
return;
}
final Player player = event.getPlayer();
if (player == null)
{
return;
}
for (SkillHolder skill : SKILLS)
{
final BuffInfo buff = player.getEffectList().getBuffInfoBySkillId(skill.getSkillId());
if (buff != null)
{
cancelQuestTimer("balthusEventBuff" + player.getObjectId(), null, player);
startQuestTimer("balthusEventBuff" + player.getObjectId(), buff.getTime() * 1000, null, player);
BalthusEventManager.getInstance().addPlayer(player);
}
}
player.sendPacket(new ExBalthusEvent(player));
}
@RegisterEvent(EventType.ON_PLAYER_LOGOUT)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void onPlayerLogout(OnPlayerLogout event)
{
if (!isEventPeriod())
{
return;
}
final Player player = event.getPlayer();
if ((player == null))
{
return;
}
cancelQuestTimer("balthusEventBuff" + player.getObjectId(), null, player);
BalthusEventManager.getInstance().removePlayer(player);
}
@RegisterEvent(EventType.ON_CREATURE_SKILL_FINISH_CAST)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void onCreatureSkillFinishCast(OnCreatureSkillFinishCast event)
{
if (!isEventPeriod())
{
return;
}
final Player player = event.getCaster().getActingPlayer();
if (player == null)
{
return;
}
for (SkillHolder skill : SKILLS)
{
if (event.getSkill() == skill.getSkill())
{
startQuestTimer("balthusEventBuff" + player.getObjectId(), skill.getSkill().getAbnormalTime() * 1000, null, player);
BalthusEventManager.getInstance().addPlayer(player);
player.sendPacket(new ExBalthusEvent(player));
}
}
}
@Override
public String onAdvEvent(String event, Npc npc, Player player)
{
if (!isEventPeriod())
{
return "Balthus Event disabled.";
}
if (event.equals("balthusEventBuff" + player.getObjectId()))
{
BalthusEventManager.getInstance().removePlayer(player);
player.sendPacket(new ExBalthusEvent(player));
}
if (event.equals("get_event_bag"))
{
if (player.getLevel() < BalthusEventManager.getInstance().getMinimalLevel())
{
return getHtm(player, "34300-7.htm").replace("%require_level%", String.valueOf(BalthusEventManager.getInstance().getMinimalLevel()));
}
else if (player.getVariables().getBoolean(BALTHUS_BAG_VAR, false))
{
return "34330-3.htm";
}
else
{
player.getVariables().set(BALTHUS_BAG_VAR, true);
player.addItem("Balthus Event", GOOD_LUCK_BAG.getId(), GOOD_LUCK_BAG.getCount(), null, true);
return "34330-2.htm";
}
}
else if (event.equals("34330.htm"))
{
return event;
}
else if (event.equals("34330-1.htm"))
{
return event;
}
else if (event.equals("34330-4.htm"))
{
return event;
}
else if (event.startsWith("exchange_coupon_"))
{
switch (event.substring(16))
{
case ("1"):
{
if (!player.destroyItemByItemId("Destroy Coupon", 81726, 1, null, true))
{
return "34330-5.htm";
}
player.addItem("Balthus Coupon", 81711, 1, null, true);
return "34330-6.htm";
}
case ("2"):
{
if (!player.destroyItemByItemId("Destroy Coupon", 81726, 1, null, true))
{
return "34330-5.htm";
}
player.addItem("Balthus Coupon", 81710, 1, null, true);
return "34330-6.htm";
}
case ("3"):
{
if (!player.destroyItemByItemId("Destroy Coupon", 81726, 1, null, true))
{
return "34330-5.htm";
}
player.addItem("Balthus Coupon", 81709, 1, null, true);
return "34330-6.htm";
}
}
}
return null;
}
@Override
public String onFirstTalk(Npc npc, Player player)
{
return npc.getId() + ".htm";
}
public static void main(String[] args)
{
new BalthusFestival();
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<event name="Balthus Event" active="30 06 2021-29 07 2021" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/eventConfig.xsd">
<!-- Reward sets on reward.xml -->
<spawnlist>
<add npc="34330" x="-14143" y="123176" z="-3096" heading="30212" /> <!-- Gludio -->
<add npc="34330" x="16354" y="142848" z="-2680" heading="14450" /> <!-- Dion -->
<add npc="34330" x="80814" y="147987" z="-3448" heading="3355" /> <!-- Giran -->
<add npc="34330" x="82008" y="53874" z="-1472" heading="3355" /> <!-- Oren -->
<add npc="34330" x="147457" y="27863" z="-2248" heading="17863" /> <!-- Aden -->
<add npc="34330" x="112172" y="220447" z="-3648" heading="30708" /> <!-- Heine -->
<add npc="34330" x="148195" y="-57368" z="-2752" heading="17863" /> <!-- Goddard -->
<add npc="34330" x="44530" y="-48368" z="-776" heading="14450" /> <!-- Rune -->
<add npc="34330" x="86897" y="-141346" z="-1320" heading="49153" /> <!-- Shutgard -->
<add npc="34330" x="-114822" y="256385" z="-1472" heading="49744" /> <!-- Talking Island -->
<add npc="34330" x="-78832" y="249115" z="-3272" heading="56380" /> <!-- Faeron Village -->
<add npc="34330" x="-80485" y="149537" z="-3016" heading="16383" /> <!-- Gluddin -->
<add npc="34330" x="117380" y="76684" z="-2672" heading="40961" /> <!-- Hunters Village -->
<add npc="34330" x="208499" y="87743" z="-1006" heading="11264" /> <!-- Arcan -->
</spawnlist>
<messages>
<add type="onEnd" text="Balthus Festival: Event end!" />
<add type="onEnter" text="Balthus Festival: Event ongoing!" />
</messages>
</event>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
https://l2central.info/main/events_and_promos/848.html?lang=en
https://l2central.info/main/events_and_promos/608.html?lang=ru
https://eu.4gameforum.com/threads/661220/
reward from - hour - to - hour
item id - item_id - count - item_count - chance - chance for been chosen like reward - chance_to_win - chance for item for been raffled;
-->
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="rewards.xsd" easyMode="true" minLevel="105" id="49783" count="100" mailSubject="Balthus Knight Lottery" mailContent="You win reward in Balthus Event!">
<reward from="11" to="19">
<items>
<item id="81453" count="1" chance="50" lotteryChance="12.5"/>
<item id="48910" count="1" chance="50" lotteryChance="12.5"/>
<item id="81832" count="1" chance="50" lotteryChance="12.5"/>
<item id="48677" count="1" chance="50" lotteryChance="12.5"/>
<item id="48678" count="1" chance="50" lotteryChance="12.5"/>
<item id="81726" count="1" chance="50" lotteryChance="12.5"/>
<item id="80501" count="1" chance="50" lotteryChance="12.5"/>
<item id="81429" count="1" chance="50" lotteryChance="12.5"/>
</items>
</reward>
<reward from="20" to="22">
<items>
<item id="35564" count="1" chance="50" lotteryChance="33"/>
<item id="29385" count="1" chance="50" lotteryChance="33"/>
<item id="19464" count="1" chance="50" lotteryChance="34"/>
</items>
</reward>
<reward from="23" to="23">
<items>
<item id="36414" count="1" chance="50" lotteryChance="100"/>
</items>
</reward>
<reward from="00" to="10">
<items>
<item id="47399" count="1" chance="50" lotteryChance="100"/>
</items>
</reward>
</list>

View File

@ -0,0 +1,41 @@
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="list">
<xs:complexType>
<xs:sequence>
<xs:element name="reward" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element name="item" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="id" use="optional"/>
<xs:attribute type="xs:int" name="count" use="optional"/>
<xs:attribute type="xs:double" name="chance" use="optional"/>
<xs:attribute type="xs:double" name="lotteryChance" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:int" name="from" use="optional"/>
<xs:attribute type="xs:int" name="to" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="easyMode"/>
<xs:attribute type="xs:int" name="minLevel"/>
<xs:attribute type="xs:int" name="id"/>
<xs:attribute type="xs:int" name="count"/>
<xs:attribute type="xs:string" name="mailSubject"/>
<xs:attribute type="xs:string" name="mailContent"/>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -102,12 +102,16 @@
<!-- Disguises you as a Balthus Knight for 2 h. Can be used only by characters of level 85 or higher. The effect is removed if you switch to a different class. -->
<set name="icon" val="icon.ev_balthus_token" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="reuse_delay" val="120000" /> <!-- 1 minute -->
<set name="material" val="PAPER" />
<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_freightable" val="true" />
<set name="handler" val="ItemSkills" />
<skills>
<skill id="27859" level="1" /> <!-- Lucky Gift Coupon (2-hour) -->
</skills>
</item>
<item id="28610" name="Veteran Duo Bracelet Pack" additionalName="Event" type="EtcItem">
<!-- Contains 1 Veteran Duo Bracelet. -->

View File

@ -1283,12 +1283,16 @@
<!-- Can apply to the Lucky Gift raffle for 2 h. Can be used only by characters of level 85 or higher. The effect is removed if you switch to a different class. -->
<set name="icon" val="icon.ev_balthus_token" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="reuse_delay" val="120000" /> <!-- 1 minute -->
<set name="material" val="PAPER" />
<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_freightable" val="true" />
<set name="material" val="PAPER" />
<set name="handler" val="ItemSkills" />
<skills>
<skill id="39171" level="1" /> <!-- Lucky Gift Coupon (2-hour) -->
</skills>
</item>
<item id="47386" name="Sibi's Letter" additionalName="Event" type="EtcItem">
<!-- Letter from Sibi, the Balthus Knights Supply Officer. -->

View File

@ -402,6 +402,14 @@
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="39171" level="2" /> <!--Lucky Gift Coupon (3-hour) -->
</skills>
</item>
<item id="48224" name="Lucky Gift Coupon" additionalName="6-hour" type="EtcItem">
<!-- For 6 h., changes the appearance of your armor into that of the Hanbok, also allows you to take part in the Lucky Gift Draw. For characters of level 85 or higher. The effect is removed if you switch to a different class. -->
@ -413,6 +421,14 @@
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="39171" level="3" /> <!--Lucky Gift Coupon (6-hour) -->
</skills>
</item>
<item id="48225" name="Festival Fairy's Five-colored Sweets" additionalName="Event" type="EtcItem">
<!-- For 30 min., Vitality bonus +30%. -->

View File

@ -740,6 +740,14 @@
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="39171" level="4" /> <!--Lucky Gift Coupon (8-hour) -->
</skills>
</item>
<item id="48854" name="1 Billion Adena Box" type="EtcItem">
<!-- Festival Fairy's gift. Double-click to obtain 1 billion adena. -->

View File

@ -86,6 +86,17 @@
<set name="is_dropable" val="false" />
<set name="is_sellable" val="false" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="reuse_delay" val="5" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="29441" level="1" /> <!-- Glowing Dragon's Attribute Potion -->
</skills>
</item>
<item id="60010" name="Pantheon's Protection Box" type="EtcItem">
<!-- Double-click to obtain 1 useful item with a certain chance. -->
@ -98,12 +109,19 @@
<item id="60011" name="Festival Fairy's Good Luck Bag" additionalName="Event" type="EtcItem">
<!-- Double-click to obtain 3 Festival Fairy's Lucky Tickets (1-hour). -->
<set name="icon" val="icon.card_event_luck_pocket" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="material" val="FISH" />
<set name="is_tradable" val="false" />
<set name="is_dropable" val="false" />
<set name="is_destroyable" val="false" />
<set name="is_sellable" val="false" />
<set name="default_action" val="PEEL" />
<set name="immediate_effect" val="true" />
<set name="material" val="PAPER" />
<set name="is_stackable" val="true" />
<set name="reuse_delay" val="86400000" /> <!-- 1 Day -->
<set name="handler" val="ExtractableItems" />
<capsuled_items>
<item id="60009" min="3" max="3" chance="100" /> <!-- Festival Fairy's Lucky Ticket -->
</capsuled_items>
</item>
<item id="60012" name="Barter Package" type="EtcItem">
<!-- Double-click to obtain rare items. -->

View File

@ -1103,8 +1103,41 @@
<skill id="27859" toLevel="1" name="Balthus Knights' Top-grade Mark">
<!-- Grants you a disguise for 2 h. You'll have a chance to receive special supplies. Acquired XP/ SP +50%. -->
<icon>icon.ev_balthus_token</icon>
<operateType>A1</operateType>
<itemConsumeCount>1</itemConsumeCount>
<itemConsumeId>28609</itemConsumeId>
<abnormalLevel>1</abnormalLevel>
<abnormalTime>7200</abnormalTime>
<abnormalType>CHANGEBODY</abnormalType>
<abnormalVisualEffect>CHANGESHAPE_TRANSFORM</abnormalVisualEffect>
<stayAfterDeath>true</stayAfterDeath>
<blockedInOlympiad>true</blockedInOlympiad>
<effectPoint>1</effectPoint>
<isMagic>4</isMagic> <!-- Magic Skill -->
<magicLevel>56</magicLevel>
<operateType>A2</operateType>
<reuseDelay>60000</reuseDelay>
<canBeDispelled>false</canBeDispelled>
<hitTime>500</hitTime>
<basicProperty>NONE</basicProperty>
<magicCriticalRate>5</magicCriticalRate>
<hitCancelTime>0</hitCancelTime>
<targetType>SELF</targetType>
<affectScope>SINGLE</affectScope>
<irreplacableBuff>true</irreplacableBuff>
<isNecessaryToggle>true</isNecessaryToggle>
<passiveConditions>
<condition name="CheckLevel">
<minLevel>85</minLevel>
</condition>
</passiveConditions>
<effects>
<effect name="ExpModify">
<amount>50</amount>
</effect>
<effect name="SpModify">
<amount>50</amount>
</effect>
</effects>
</skill>
<skill id="27860" toLevel="1" name="Royal R99-grade White Save Ticket - Armor">
<operateType>A1</operateType>

View File

@ -1969,7 +1969,74 @@
<skill id="29441" toLevel="1" name="Lucky Gift Coupon (1-hour)">
<!-- For $s1, PvE damage +10%, Attribute Resistance +20, acquired XP +10%. Allows to take part in the raffle. -->
<icon>icon.skill0000</icon>
<operateType>A1</operateType>
<itemConsumeCount>1</itemConsumeCount>
<itemConsumeId>60009</itemConsumeId>
<abnormalLevel>1</abnormalLevel>
<abnormalTime>3600</abnormalTime>
<abnormalType>CHANGEBODY</abnormalType>
<abnormalVisualEffect>CHANGESHAPE_TRANSFORM</abnormalVisualEffect>
<stayAfterDeath>true</stayAfterDeath>
<blockedInOlympiad>true</blockedInOlympiad>
<effectPoint>1</effectPoint>
<isMagic>4</isMagic> <!-- Magic Skill -->
<magicLevel>56</magicLevel>
<operateType>A2</operateType>
<reuseDelay>60000</reuseDelay>
<canBeDispelled>false</canBeDispelled>
<hitTime>500</hitTime>
<basicProperty>NONE</basicProperty>
<magicCriticalRate>5</magicCriticalRate>
<hitCancelTime>0</hitCancelTime>
<targetType>SELF</targetType>
<affectScope>SINGLE</affectScope>
<irreplacableBuff>true</irreplacableBuff>
<isNecessaryToggle>true</isNecessaryToggle>
<passiveConditions>
<condition name="CheckLevel">
<minLevel>85</minLevel>
</condition>
</passiveConditions>
<effects>
<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="DefenceAttribute">
<amount>20</amount>
<attribute>FIRE</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>WATER</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>EARTH</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>WIND</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>HOLY</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>DARK</attribute>
</effect>
<effect name="ExpModify">
<amount>10</amount>
</effect>
</effects>
</skill>
<skill id="29442" toLevel="1" name="Freya's Lucky Pouch">
<icon>icon.skill0000</icon>

View File

@ -47,10 +47,18 @@
<value level="4">icon.etc_lottery_card_i00</value>
<value level="5">icon.christmas_card_box2</value>
</icon>
<itemConsumeCount>1</itemConsumeCount>
<itemConsumeId>49784</itemConsumeId>
<abnormalLevel>1</abnormalLevel>
<abnormalTime>3600</abnormalTime>
<abnormalLevel>
<value level="1">1</value>
<value level="2">2</value>
<value level="3">3</value>
<value level="4">4</value>
</abnormalLevel>
<abnormalTime>
<value level="1">3600</value>
<value level="2">7200</value>
<value level="3">21600</value>
<value level="4">28800</value>
</abnormalTime>
<abnormalType>CHANGEBODY</abnormalType>
<abnormalVisualEffect>CHANGESHAPE_TRANSFORM</abnormalVisualEffect>
<stayAfterDeath>true</stayAfterDeath>
@ -67,6 +75,8 @@
<hitCancelTime>0</hitCancelTime>
<targetType>SELF</targetType>
<affectScope>SINGLE</affectScope>
<isNecessaryToggle>true</isNecessaryToggle>
<irreplacableBuff>true</irreplacableBuff>
<passiveConditions>
<condition name="CheckLevel">
<minLevel>85</minLevel>

View File

@ -0,0 +1,407 @@
/*
* 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.instancemanager.events;
import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.l2jmobius.commons.threads.ThreadPool;
import org.l2jmobius.commons.util.Chronos;
import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.commons.util.Rnd;
import org.l2jmobius.gameserver.enums.MailType;
import org.l2jmobius.gameserver.instancemanager.MailManager;
import org.l2jmobius.gameserver.model.Message;
import org.l2jmobius.gameserver.model.StatSet;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.item.instance.Item;
import org.l2jmobius.gameserver.model.itemcontainer.Mail;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEvent;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEventJackpotUser;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Index
*/
public class BalthusEventManager implements IXmlReader
{
protected static final Logger LOGGER = Logger.getLogger(BalthusEventManager.class.getName());
private final Set<Player> _players = ConcurrentHashMap.newKeySet();
private final Map<Integer, BalthusEventHolder> _templates = new HashMap<>();
private boolean _isEasyMode;
private ItemHolder _consolation;
private int _minimalLevel = 0;
private String _mailSubject = null;
private String _mailContent = null;
private boolean _isRunning = false;
private int _currProgress;
private int _currState;
private int _avoidMinutesIssue;
private Player _winner = null;
private ItemChanceHolder _rewardItem;
public void addPlayer(Player player)
{
_players.add(player);
}
public void removePlayer(Player player)
{
_players.remove(player);
}
public Set<Player> getPlayers()
{
return _players;
}
public void removeParticipant(Player player)
{
_players.remove(player);
}
public boolean isPlayerParticipant(Player player)
{
return _players.contains(player);
}
public int getMinimalLevel()
{
return _minimalLevel;
}
public int getCurrentProgress()
{
return _currProgress;
}
public int getCurrentState()
{
return _currState;
}
public ItemHolder getConsolation()
{
return _consolation;
}
public int getCurrRewardItem()
{
return _rewardItem.getId();
}
public boolean isRunning()
{
return _isRunning;
}
public int getTime()
{
return Calendar.getInstance().get(Calendar.MINUTE) * 60; // client makes 3600 - time
}
protected BalthusEventManager()
{
load();
final long currentTime = Chronos.currentTimeMillis();
final Calendar calendar = Calendar.getInstance();
final long hours = calendar.get(Calendar.HOUR_OF_DAY);
final long mins = calendar.get(Calendar.MINUTE);
long startDelay;
if (mins <= 11)
{
calendar.set(Calendar.MINUTE, 12);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 20;
_avoidMinutesIssue = 1;
}
else if (mins <= 23)
{
calendar.set(Calendar.MINUTE, 24);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 40;
_avoidMinutesIssue = 2;
}
else if (mins <= 35)
{
calendar.set(Calendar.MINUTE, 36);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 60;
_avoidMinutesIssue = 3;
}
else if (mins <= 47)
{
calendar.set(Calendar.MINUTE, 48);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 80;
_avoidMinutesIssue = 4;
}
else
{
calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + 1);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 100;
_avoidMinutesIssue = 5;
}
if (((hours > 11) && (hours < 23)) || (hours == 23))
{
_currState = (int) hours - 11;
}
else
{
_currState = (int) hours + 13;
}
getNewRewardItem();
ThreadPool.scheduleAtFixedRate(this::tryToGetWinner, startDelay, 720000);
}
@Override
public synchronized void load()
{
_templates.clear();
parseDatapackFile("data/scripts/events/BalthusFestival/rewards.xml");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _templates.size() + " rewards.");
}
@Override
public void parseDocument(Document doc, File f)
{
final AtomicInteger i = new AtomicInteger();
forEach(doc, "list", listNode ->
{
final StatSet set = new StatSet(parseAttributes(listNode));
if (_minimalLevel == 0)
{
_isEasyMode = set.getBoolean("easyMode", false);
_minimalLevel = set.getInt("minLevel", 85);
_consolation = new ItemHolder(set.getInt("id", 49783), set.getInt("count", 100));
_mailSubject = set.getString("mailSubject", "Balthus Knight Lottery");
_mailContent = set.getString("mailContent", "You win reward in Balthus Event!");
}
forEach(listNode, "reward", reward ->
{
final AtomicInteger j = new AtomicInteger();
final Map<Integer, Map<ItemChanceHolder, Double>> tempRewardList = new HashMap<>();
final Map<Integer, Integer> rewardTime = new HashMap<>();
final StatSet rewardSet = new StatSet(parseAttributes(reward));
rewardTime.put(rewardSet.getInt("from"), rewardSet.getInt("to", rewardSet.getInt("from")));
forEach(reward, "items", itemNode ->
{
forEach(itemNode, "item", item ->
{
final Map<ItemChanceHolder, Double> tempChanceRewardList = new HashMap<>();
j.getAndIncrement();
final StatSet itemSet = new StatSet(parseAttributes(item));
ItemChanceHolder itemChanceHolder = new ItemChanceHolder(itemSet.getInt("id", 57), itemSet.getDouble("chance", 100), itemSet.getInt("count", 100));
tempChanceRewardList.put(itemChanceHolder, itemSet.getDouble("lotteryChance", 0.0));
tempRewardList.put(j.intValue(), tempChanceRewardList);
});
i.getAndIncrement();
_templates.put(i.intValue(), new BalthusEventHolder(rewardTime, tempRewardList));
});
});
});
}
private void tryToGetWinner()
{
_avoidMinutesIssue++;
if (_isRunning && (_avoidMinutesIssue != 6))
{
return;
}
final int random = Rnd.get(100);
if (!_isRunning && (random >= _rewardItem.getChance()) && !_players.isEmpty())
{
final List<Player> playerList = new ArrayList<>(_players);
Collections.shuffle(playerList);
for (Player player : playerList)
{
if (player.getLevel() >= getMinimalLevel())
{
_winner = player;
}
}
if (_winner != null)
{
LOGGER.info(getClass().getSimpleName() + ": New winner for " + _currState + " of Balthus Event is " + _winner.getName() + " - " + _winner.getObjectId() + ". Player win " + new Item(_rewardItem.getId()).getItemName() + " - " + _rewardItem.getId() + " count: " + _rewardItem.getCount() + ".");
Broadcast.toAllOnlinePlayers(new ExBalthusEventJackpotUser());
Broadcast.toAllOnlinePlayers(new SystemMessage(SystemMessageId.S1_HAS_OBTAINED_S2_FROM_THE_FESTIVAL_FAIRY).addPcName(_winner).addItemName(_rewardItem.getId()));
_isRunning = true;
sendConsolationItemsToAll();
sendRewardToPlayer(_winner);
}
else
{
_currProgress += 20;
}
}
else
{
_currProgress += 20;
}
if (_avoidMinutesIssue == 6)
{
resetCurrentStage();
}
for (Player player : World.getInstance().getPlayers())
{
player.sendPacket(new ExBalthusEvent(player));
}
}
private void resetCurrentStage()
{
_currState += 1;
_winner = null;
if (_currState == 25)
{
_currState = 1;
}
_currProgress = 20;
if (!_isRunning && _isEasyMode)
{
sendConsolationItemsToAll();
}
_isRunning = false;
_rewardItem = null;
_avoidMinutesIssue = 1;
getNewRewardItem();
}
private void sendConsolationItemsToAll()
{
for (Player player : _players)
{
if (player == _winner)
{
continue;
}
player.getVariables().set(PlayerVariables.BALTHUS_REWARD, player.getVariables().getInt(PlayerVariables.BALTHUS_REWARD, 0) + _consolation.getCount());
player.sendPacket(new SystemMessage(SystemMessageId.YOU_VE_OBTAINED_S1_FAIRY_S_LUCKY_COINS).addInt((int) _consolation.getCount()));
}
}
private void getNewRewardItem()
{
while (_rewardItem == null)
{
for (BalthusEventHolder holder : _templates.values())
{
if (holder.getRewardTime() == null)
{
continue;
}
final Map<Integer, Integer> rewardTime = holder.getRewardTime();
final int firstParam = rewardTime.keySet().iterator().hasNext() ? rewardTime.keySet().iterator().next() : 0;
final Calendar calendar = Calendar.getInstance();
if ((firstParam <= calendar.get(Calendar.HOUR_OF_DAY)) && (calendar.get(Calendar.HOUR_OF_DAY) <= rewardTime.get(firstParam)))
{
final double random = Rnd.get(100d);
double chance = 0;
for (Map<ItemChanceHolder, Double> map : holder.getRewardList().values())
{
for (Entry<ItemChanceHolder, Double> entry : map.entrySet())
{
chance += entry.getValue();
if (chance >= random)
{
_rewardItem = entry.getKey();
LOGGER.info(getClass().getSimpleName() + ": Reward for " + _currState + " stage set. Next reward item is " + new Item(_rewardItem.getId()).getItemName() + " - " + _rewardItem.getId() + " count: " + _rewardItem.getCount() + ".");
break;
}
}
if (_rewardItem != null)
{
break;
}
}
}
}
}
}
private void sendRewardToPlayer(Player player)
{
final Message msg = new Message(player.getObjectId(), _mailSubject, _mailContent, MailType.NEWS_INFORMER);
final Mail attachments = msg.createAttachments();
attachments.addItem("Balthus Knight Lottery", _rewardItem.getId(), _rewardItem.getCount(), null, null);
MailManager.getInstance().sendMessage(msg);
}
public static class BalthusEventHolder
{
// From hour to hour.
private final Map<Integer, Integer> _rewardTime;
// Time reward - Reward item, chance to put in lottery.
private final Map<Integer, Map<ItemChanceHolder, Double>> _rewardList;
public BalthusEventHolder(Map<Integer, Integer> rewardTime, Map<Integer, Map<ItemChanceHolder, Double>> rewardList)
{
_rewardTime = rewardTime;
_rewardList = rewardList;
}
public Map<Integer, Integer> getRewardTime()
{
return _rewardTime;
}
public Map<Integer, Map<ItemChanceHolder, Double>> getRewardList()
{
return _rewardList;
}
}
public static BalthusEventManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final BalthusEventManager INSTANCE = new BalthusEventManager();
}
}

View File

@ -63,6 +63,7 @@ public class PlayerVariables extends AbstractVariables
public static final String CLAN_CONTRIBUTION = "CLAN_CONTRIBUTION";
public static final String CLAN_CONTRIBUTION_TOTAL = "CLAN_CONTRIBUTION_TOTAL";
public static final String CLAN_CONTRIBUTION_REWARDED = "CLAN_CONTRIBUTION_REWARDED";
public static final String BALTHUS_REWARD = "BALTHUS_REWARD";
public static final String AUTO_USE_SETTINGS = "AUTO_USE_SETTINGS";
public static final String AUTO_USE_SHORTCUTS = "AUTO_USE_SHORTCUTS";
public static final String HUNTING_ZONE_ENTRY = "HUNTING_ZONE_ENTRY_";

View File

@ -48,6 +48,7 @@ import org.l2jmobius.gameserver.network.clientpackets.attributechange.SendChange
import org.l2jmobius.gameserver.network.clientpackets.autoplay.ExAutoPlaySetting;
import org.l2jmobius.gameserver.network.clientpackets.autoplay.ExRequestActivateAutoShortcut;
import org.l2jmobius.gameserver.network.clientpackets.awakening.RequestCallToChangeClass;
import org.l2jmobius.gameserver.network.clientpackets.balthusevent.RequestEventBalthusToken;
import org.l2jmobius.gameserver.network.clientpackets.ceremonyofchaos.RequestCancelCuriousHouse;
import org.l2jmobius.gameserver.network.clientpackets.ceremonyofchaos.RequestCuriousHouseHtml;
import org.l2jmobius.gameserver.network.clientpackets.ceremonyofchaos.RequestJoinCuriousHouse;
@ -437,7 +438,7 @@ public enum ExIncomingPackets implements IIncomingPackets<GameClient>
REQUEST_CHECK_AGIT_DECO_AVAILABILITY(0x117, null, ConnectionState.IN_GAME),
REQUEST_USER_FACTION_INFO(0x118, RequestUserFactionInfo::new, ConnectionState.IN_GAME),
EX_EXIT_ARENA(0x119, null, ConnectionState.IN_GAME),
REQUEST_EVENT_BALTHUS_TOKEN(0x11A, null, ConnectionState.IN_GAME),
REQUEST_EVENT_BALTHUS_TOKEN(0x11A, RequestEventBalthusToken::new, ConnectionState.IN_GAME),
REQUEST_PARTY_MATCHING_HISTORY(0x11B, null, ConnectionState.IN_GAME),
EX_ARENA_CUSTOM_NOTIFICATION(0x11C, null, ConnectionState.IN_GAME),
REQUEST_TODO_LIST(0x11D, null, ConnectionState.IN_GAME),

View File

@ -0,0 +1,63 @@
/*
* 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.balthusevent;
import org.l2jmobius.commons.network.PacketReader;
import org.l2jmobius.gameserver.instancemanager.events.BalthusEventManager;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEvent;
/**
* @author Index
*/
public class RequestEventBalthusToken implements IClientIncomingPacket
{
@Override
public boolean read(GameClient client, PacketReader packet)
{
return true;
}
@Override
public void run(GameClient client)
{
final Player player = client.getPlayer();
if (player == null)
{
return;
}
final int count = player.getVariables().getInt(PlayerVariables.BALTHUS_REWARD, 0);
if (count != 0)
{
if (player.addItem("Balthus Consolation Item", BalthusEventManager.getInstance().getConsolation().getId(), count, player, true) != null)
{
player.getVariables().set(PlayerVariables.BALTHUS_REWARD, 0);
player.sendPacket(new ExBalthusEvent(player));
}
}
else
{
player.sendPacket(new SystemMessage(SystemMessageId.NO_FAIRY_S_LUCKY_COINS_AVAILABLE));
}
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.balthusevent;
import org.l2jmobius.commons.network.PacketWriter;
import org.l2jmobius.gameserver.instancemanager.events.BalthusEventManager;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.network.OutgoingPackets;
import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
/**
* Consolation prize changing in SysTextures/ui6.ugx file "RewardClip.as" -> configUI -> this.tokenItemID = 49783;
* @author Index
*/
public class ExBalthusEvent implements IClientOutgoingPacket
{
private final Player _player;
public ExBalthusEvent(Player player)
{
_player = player;
}
@Override
public boolean write(PacketWriter packet)
{
OutgoingPackets.EX_BALTHUS_EVENT.writeId(packet);
packet.writeD(BalthusEventManager.getInstance().getCurrentState()); // CurrentState (max 24, because 1 state going 1 hour)
packet.writeD(BalthusEventManager.getInstance().getCurrentProgress()); // Progress
packet.writeD(BalthusEventManager.getInstance().getCurrRewardItem()); // CurrentRewardItem (current event item, what can be rewarded)
packet.writeD(_player.getVariables().getInt(PlayerVariables.BALTHUS_REWARD, 0)); // RewardTokenCount (current items for withdraw (available rewards))
packet.writeD((int) BalthusEventManager.getInstance().getConsolation().getCount()); // CurrentTokenCount (current count of "consolation prize")
packet.writeD(BalthusEventManager.getInstance().isPlayerParticipant(_player) ? 1 : 0); // Participated (player in event?)
packet.writeC(BalthusEventManager.getInstance().isRunning() ? 0 : 1); // Running (0 - already someone get this reward ? / 1 - item can be rewarded)
packet.writeD(BalthusEventManager.getInstance().getTime()); // Time (in seconds)
return true;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.balthusevent;
import org.l2jmobius.commons.network.PacketWriter;
import org.l2jmobius.gameserver.network.OutgoingPackets;
import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
/**
* @author Index
*/
public class ExBalthusEventJackpotUser implements IClientOutgoingPacket
{
public static final ExBalthusEventJackpotUser STATIC_PACKET = new ExBalthusEventJackpotUser();
@Override
public boolean write(PacketWriter packet)
{
OutgoingPackets.EX_BALTHUS_EVENT_JACKPOT_USER.writeId(packet);
return true;
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/multisell.xsd">
<npcs>
<npc>34330</npc> <!-- Festival Fairy -->
</npcs>
<item>
<ingredient id="49783" count="70" /> <!-- Fairy's Lucky Coin -->
<ingredient id="57" count="100000" /> <!-- Adena -->
<production id="81707" count="1" /> <!-- Festival Fairy's Gift - Event -->
</item>
<item>
<ingredient id="49783" count="8" /> <!-- Fairy's Lucky Coin -->
<ingredient id="57" count="500000" /> <!-- Adena -->
<production id="80934" count="1" /> <!-- Festival Fairy's Box: Crystals - Event -->
</item>
<item>
<ingredient id="49783" count="20" /> <!-- Fairy's Lucky Coin -->
<production id="48229" count="1" /> <!-- Party Summoning Scroll -->
</item>
<item>
<ingredient id="49783" count="25" /> <!-- Fairy's Lucky Coin -->
<production id="13302" count="1" /> <!-- My Teleport Scroll - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81869" count="1" /> <!-- Superior Ruby Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81870" count="1" /> <!-- Superior Sapphire Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81871" count="1" /> <!-- Superior Red Cat's Eye Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="6750" /> <!-- Fairy's Lucky Coin -->
<production id="81872" count="1" /> <!-- Superior Blue Cat's Eye Lv. 10 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80472" count="1" /> <!-- Greater Topaz Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80475" count="1" /> <!-- Greater Obsidian Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80476" count="1" /> <!-- Greater Opal Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80477" count="1" /> <!-- Greater Emerald Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80478" count="1" /> <!-- Greater Aquamarine Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80479" count="1" /> <!-- Greater Diamond Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80480" count="1" /> <!-- Greater Pearl Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80481" count="1" /> <!-- Greater Vital Stone Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="100" /> <!-- Fairy's Lucky Coin -->
<production id="80482" count="1" /> <!-- Greater Garnet Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="200" /> <!-- Fairy's Lucky Coin -->
<production id="80483" count="1" /> <!-- Greater Tanzanite Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="500" /> <!-- Fairy's Lucky Coin -->
<production id="80484" count="1" /> <!-- Greater Red Cat's Eye Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="500" /> <!-- Fairy's Lucky Coin -->
<production id="80485" count="1" /> <!-- Greater Blue Cat's Eye Lv. 1 - Event -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80486" count="1" /> <!-- Mysterious Talisman - STR - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80487" count="1" /> <!-- Mysterious Talisman - INT - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80488" count="1" /> <!-- Mysterious Talisman - DEX - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80489" count="1" /> <!-- Mysterious Talisman - WIT - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80490" count="1" /> <!-- Mysterious Talisman - CON - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80491" count="1" /> <!-- Mysterious Talisman - MEN - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80492" count="1" /> <!-- Mysterious Talisman - Attribute Attack - 7-day -->
</item>
<item>
<ingredient id="49783" count="250" /> <!-- Fairy's Lucky Coin -->
<production id="80493" count="1" /> <!-- Mysterious Talisman - Attribute Resistance - 7-day -->
</item>
</list>

View File

@ -0,0 +1,6 @@
<html><body>Event Manager Festival Fairy:<br>
Every hour I was trying raffle the item of all the player.<br>
For start to be participant - you need to get coupon and use it.<br>
Every day you can get 3 coupons from the Bag and I can sell you more coupons.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,5 @@
<html><body>Event Manager Festival Fairy:<br>
Here we go.<br>
I give you this bag, but on event period you can get only one!<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,4 @@
<html><body>Event Manager Festival Fairy:<br>
Sorry, but you already have your Event Bag.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,6 @@
<html><body>Event Manager Festival Fairy:<br>
I can exchange coupons for you, let me see on your coupon.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival exchange_coupon_1">+6 Leviathan Robe</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival exchange_coupon_2">+6 Leviathan Light Armor</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival exchange_coupon_3">+6 Leviathan Heavy Armor</Button>
</body></html>

View File

@ -0,0 +1,4 @@
<html><body>Event Manager Festival Fairy:<br>
Sorry, but you don't have required coupon.<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,4 @@
<html><body>Event Manager Festival Fairy:<br>
Good luck in next raffle!<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,5 @@
<html><body>Event Manager Festival Fairy:<br>
I cant give you Bags with Coupons, because you level is too small!<br>
Back to me, when your level will be %require_level%<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330.htm">Back</Button>
</body></html>

View File

@ -0,0 +1,10 @@
<html><body>Event Manager Festival Fairy:<br>
Hello! Are you want to win some reward today?<br>
Don't worry, I will give for all player's consolation reward if someone won reward!<br>
If you have some Fairy Coins - I can exchange it on items for you.<br>
Good luck!<br>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330-1.htm">Learn more about the event</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h npc_%objectId%_multisell 343300001">Exchange coins on items</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival 34330-4.htm">I want to exchange reward coupon</Button>
<Button ALIGN=LEFT ICON="NORMAL" action="bypass -h Quest BalthusFestival get_event_bag">Give me Event Bag for taking Coupons</Button>
</body></html>

View File

@ -0,0 +1,236 @@
/*
* 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 events.BalthusFestival;
import java.util.ArrayList;
import java.util.List;
import org.l2jmobius.gameserver.instancemanager.events.BalthusEventManager;
import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.events.EventType;
import org.l2jmobius.gameserver.model.events.ListenerRegisterType;
import org.l2jmobius.gameserver.model.events.annotations.RegisterEvent;
import org.l2jmobius.gameserver.model.events.annotations.RegisterType;
import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSkillFinishCast;
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.holders.ItemHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.quest.LongTimeEvent;
import org.l2jmobius.gameserver.model.skill.BuffInfo;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEvent;
/**
* @author Index
*/
public class BalthusFestival extends LongTimeEvent
{
// NPC
private static final int FESTIVAL_FAIRY = 34330;
// Item
private static final ItemHolder GOOD_LUCK_BAG = new ItemHolder(60011, 1); // Festival Fairy's Good Luck Bag
// Skills
private static final List<SkillHolder> SKILLS = new ArrayList<>(8);
static
{
SKILLS.add(new SkillHolder(29441, 1)); // Fairy_Coupon_1_Hour
SKILLS.add(new SkillHolder(39171, 1)); // Fairy_Coupon_2_Hour
SKILLS.add(new SkillHolder(39171, 2)); // Fairy_Coupon_3_Hour
SKILLS.add(new SkillHolder(39171, 3)); // Fairy_Coupon_6_Hour
SKILLS.add(new SkillHolder(39171, 4)); // Fairy_Coupon_8_Hour
SKILLS.add(new SkillHolder(39171, 5)); // Fairy_Coupon_Unlimited_Hour
SKILLS.add(new SkillHolder(27859, 1)); // Balthus_Coupon_2_Hour
SKILLS.add(new SkillHolder(48853, 1)); // Balthus_Coupon_2_Hour
}
// Misc
private static final String BALTHUS_BAG_VAR = "BALTHUS_BAG";
private BalthusFestival()
{
addStartNpc(FESTIVAL_FAIRY);
addFirstTalkId(FESTIVAL_FAIRY);
addTalkId(FESTIVAL_FAIRY);
if (isEventPeriod())
{
BalthusEventManager.getInstance();
}
}
@RegisterEvent(EventType.ON_PLAYER_LOGIN)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void onPlayerLogin(OnPlayerLogin event)
{
if (!isEventPeriod())
{
return;
}
final Player player = event.getPlayer();
if (player == null)
{
return;
}
for (SkillHolder skill : SKILLS)
{
final BuffInfo buff = player.getEffectList().getBuffInfoBySkillId(skill.getSkillId());
if (buff != null)
{
cancelQuestTimer("balthusEventBuff" + player.getObjectId(), null, player);
startQuestTimer("balthusEventBuff" + player.getObjectId(), buff.getTime() * 1000, null, player);
BalthusEventManager.getInstance().addPlayer(player);
}
}
player.sendPacket(new ExBalthusEvent(player));
}
@RegisterEvent(EventType.ON_PLAYER_LOGOUT)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void onPlayerLogout(OnPlayerLogout event)
{
if (!isEventPeriod())
{
return;
}
final Player player = event.getPlayer();
if ((player == null))
{
return;
}
cancelQuestTimer("balthusEventBuff" + player.getObjectId(), null, player);
BalthusEventManager.getInstance().removePlayer(player);
}
@RegisterEvent(EventType.ON_CREATURE_SKILL_FINISH_CAST)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void onCreatureSkillFinishCast(OnCreatureSkillFinishCast event)
{
if (!isEventPeriod())
{
return;
}
final Player player = event.getCaster().getActingPlayer();
if (player == null)
{
return;
}
for (SkillHolder skill : SKILLS)
{
if (event.getSkill() == skill.getSkill())
{
startQuestTimer("balthusEventBuff" + player.getObjectId(), skill.getSkill().getAbnormalTime() * 1000, null, player);
BalthusEventManager.getInstance().addPlayer(player);
player.sendPacket(new ExBalthusEvent(player));
}
}
}
@Override
public String onAdvEvent(String event, Npc npc, Player player)
{
if (!isEventPeriod())
{
return "Balthus Event disabled.";
}
if (event.equals("balthusEventBuff" + player.getObjectId()))
{
BalthusEventManager.getInstance().removePlayer(player);
player.sendPacket(new ExBalthusEvent(player));
}
if (event.equals("get_event_bag"))
{
if (player.getLevel() < BalthusEventManager.getInstance().getMinimalLevel())
{
return getHtm(player, "34300-7.htm").replace("%require_level%", String.valueOf(BalthusEventManager.getInstance().getMinimalLevel()));
}
else if (player.getVariables().getBoolean(BALTHUS_BAG_VAR, false))
{
return "34330-3.htm";
}
else
{
player.getVariables().set(BALTHUS_BAG_VAR, true);
player.addItem("Balthus Event", GOOD_LUCK_BAG.getId(), GOOD_LUCK_BAG.getCount(), null, true);
return "34330-2.htm";
}
}
else if (event.equals("34330.htm"))
{
return event;
}
else if (event.equals("34330-1.htm"))
{
return event;
}
else if (event.equals("34330-4.htm"))
{
return event;
}
else if (event.startsWith("exchange_coupon_"))
{
switch (event.substring(16))
{
case ("1"):
{
if (!player.destroyItemByItemId("Destroy Coupon", 81726, 1, null, true))
{
return "34330-5.htm";
}
player.addItem("Balthus Coupon", 81711, 1, null, true);
return "34330-6.htm";
}
case ("2"):
{
if (!player.destroyItemByItemId("Destroy Coupon", 81726, 1, null, true))
{
return "34330-5.htm";
}
player.addItem("Balthus Coupon", 81710, 1, null, true);
return "34330-6.htm";
}
case ("3"):
{
if (!player.destroyItemByItemId("Destroy Coupon", 81726, 1, null, true))
{
return "34330-5.htm";
}
player.addItem("Balthus Coupon", 81709, 1, null, true);
return "34330-6.htm";
}
}
}
return null;
}
@Override
public String onFirstTalk(Npc npc, Player player)
{
return npc.getId() + ".htm";
}
public static void main(String[] args)
{
new BalthusFestival();
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<event name="Balthus Event" active="30 06 2021-29 07 2021" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/eventConfig.xsd">
<!-- Reward sets on reward.xml -->
<spawnlist>
<add npc="34330" x="-14143" y="123176" z="-3096" heading="30212" /> <!-- Gludio -->
<add npc="34330" x="16354" y="142848" z="-2680" heading="14450" /> <!-- Dion -->
<add npc="34330" x="80814" y="147987" z="-3448" heading="3355" /> <!-- Giran -->
<add npc="34330" x="82008" y="53874" z="-1472" heading="3355" /> <!-- Oren -->
<add npc="34330" x="147457" y="27863" z="-2248" heading="17863" /> <!-- Aden -->
<add npc="34330" x="112172" y="220447" z="-3648" heading="30708" /> <!-- Heine -->
<add npc="34330" x="148195" y="-57368" z="-2752" heading="17863" /> <!-- Goddard -->
<add npc="34330" x="44530" y="-48368" z="-776" heading="14450" /> <!-- Rune -->
<add npc="34330" x="86897" y="-141346" z="-1320" heading="49153" /> <!-- Shutgard -->
<add npc="34330" x="-114822" y="256385" z="-1472" heading="49744" /> <!-- Talking Island -->
<add npc="34330" x="-78832" y="249115" z="-3272" heading="56380" /> <!-- Faeron Village -->
<add npc="34330" x="-80485" y="149537" z="-3016" heading="16383" /> <!-- Gluddin -->
<add npc="34330" x="117380" y="76684" z="-2672" heading="40961" /> <!-- Hunters Village -->
<add npc="34330" x="208499" y="87743" z="-1006" heading="11264" /> <!-- Arcan -->
</spawnlist>
<messages>
<add type="onEnd" text="Balthus Festival: Event end!" />
<add type="onEnter" text="Balthus Festival: Event ongoing!" />
</messages>
</event>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
https://l2central.info/main/events_and_promos/848.html?lang=en
https://l2central.info/main/events_and_promos/608.html?lang=ru
https://eu.4gameforum.com/threads/661220/
reward from - hour - to - hour
item id - item_id - count - item_count - chance - chance for been chosen like reward - chance_to_win - chance for item for been raffled;
-->
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="rewards.xsd" easyMode="true" minLevel="105" id="49783" count="100" mailSubject="Balthus Knight Lottery" mailContent="You win reward in Balthus Event!">
<reward from="11" to="19">
<items>
<item id="81453" count="1" chance="50" lotteryChance="12.5"/>
<item id="48910" count="1" chance="50" lotteryChance="12.5"/>
<item id="81832" count="1" chance="50" lotteryChance="12.5"/>
<item id="48677" count="1" chance="50" lotteryChance="12.5"/>
<item id="48678" count="1" chance="50" lotteryChance="12.5"/>
<item id="81726" count="1" chance="50" lotteryChance="12.5"/>
<item id="80501" count="1" chance="50" lotteryChance="12.5"/>
<item id="81429" count="1" chance="50" lotteryChance="12.5"/>
</items>
</reward>
<reward from="20" to="22">
<items>
<item id="35564" count="1" chance="50" lotteryChance="33"/>
<item id="29385" count="1" chance="50" lotteryChance="33"/>
<item id="19464" count="1" chance="50" lotteryChance="34"/>
</items>
</reward>
<reward from="23" to="23">
<items>
<item id="36414" count="1" chance="50" lotteryChance="100"/>
</items>
</reward>
<reward from="00" to="10">
<items>
<item id="47399" count="1" chance="50" lotteryChance="100"/>
</items>
</reward>
</list>

View File

@ -0,0 +1,41 @@
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="list">
<xs:complexType>
<xs:sequence>
<xs:element name="reward" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element name="item" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="id" use="optional"/>
<xs:attribute type="xs:int" name="count" use="optional"/>
<xs:attribute type="xs:double" name="chance" use="optional"/>
<xs:attribute type="xs:double" name="lotteryChance" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:int" name="from" use="optional"/>
<xs:attribute type="xs:int" name="to" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="easyMode"/>
<xs:attribute type="xs:int" name="minLevel"/>
<xs:attribute type="xs:int" name="id"/>
<xs:attribute type="xs:int" name="count"/>
<xs:attribute type="xs:string" name="mailSubject"/>
<xs:attribute type="xs:string" name="mailContent"/>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -102,12 +102,16 @@
<!-- Disguises you as a Balthus Knight for 2 h. Can be used only by characters of level 85 or higher. The effect is removed if you switch to a different class. -->
<set name="icon" val="icon.ev_balthus_token" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="reuse_delay" val="120000" /> <!-- 1 minute -->
<set name="material" val="PAPER" />
<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_freightable" val="true" />
<set name="handler" val="ItemSkills" />
<skills>
<skill id="27859" level="1" /> <!-- Lucky Gift Coupon (2-hour) -->
</skills>
</item>
<item id="28610" name="Veteran Duo Bracelet Pack" additionalName="Event" type="EtcItem">
<!-- Contains 1 Veteran Duo Bracelet. -->

View File

@ -1283,12 +1283,16 @@
<!-- Can apply to the Lucky Gift raffle for 2 h. Can be used only by characters of level 85 or higher. The effect is removed if you switch to a different class. -->
<set name="icon" val="icon.ev_balthus_token" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="reuse_delay" val="120000" /> <!-- 1 minute -->
<set name="material" val="PAPER" />
<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_freightable" val="true" />
<set name="material" val="PAPER" />
<set name="handler" val="ItemSkills" />
<skills>
<skill id="39171" level="1" /> <!-- Lucky Gift Coupon (2-hour) -->
</skills>
</item>
<item id="47386" name="Sibi's Letter" additionalName="Event" type="EtcItem">
<!-- Letter from Sibi, the Balthus Knights Supply Officer. -->

View File

@ -402,6 +402,14 @@
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="39171" level="2" /> <!--Lucky Gift Coupon (3-hour) -->
</skills>
</item>
<item id="48224" name="Lucky Gift Coupon" additionalName="6-hour" type="EtcItem">
<!-- For 6 h., changes the appearance of your armor into that of the Hanbok, also allows you to take part in the Lucky Gift Draw. For characters of level 85 or higher. The effect is removed if you switch to a different class. -->
@ -413,6 +421,14 @@
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="39171" level="3" /> <!--Lucky Gift Coupon (6-hour) -->
</skills>
</item>
<item id="48225" name="Festival Fairy's Five-colored Sweets" additionalName="Event" type="EtcItem">
<!-- For 30 min., Vitality bonus +30%. -->

View File

@ -740,6 +740,14 @@
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="39171" level="4" /> <!--Lucky Gift Coupon (8-hour) -->
</skills>
</item>
<item id="48854" name="1 Billion Adena Box" type="EtcItem">
<!-- Festival Fairy's gift. Double-click to obtain 1 billion adena. -->

View File

@ -86,6 +86,17 @@
<set name="is_dropable" val="false" />
<set name="is_sellable" val="false" />
<set name="is_freightable" val="true" />
<set name="immediate_effect" val="true" />
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="is_oly_restricted" val="true" />
<set name="is_event_restricted" val="true" />
<set name="handler" val="ItemSkills" />
<set name="reuse_delay" val="5" />
<set name="etcitem_type" val="SCROLL" />
<skills>
<skill id="29441" level="1" /> <!-- Glowing Dragon's Attribute Potion -->
</skills>
</item>
<item id="60010" name="Pantheon's Protection Box" type="EtcItem">
<!-- Double-click to obtain 1 useful item with a certain chance. -->
@ -98,12 +109,19 @@
<item id="60011" name="Festival Fairy's Good Luck Bag" additionalName="Event" type="EtcItem">
<!-- Double-click to obtain 3 Festival Fairy's Lucky Tickets (1-hour). -->
<set name="icon" val="icon.card_event_luck_pocket" />
<set name="default_action" val="SKILL_REDUCE" />
<set name="material" val="FISH" />
<set name="is_tradable" val="false" />
<set name="is_dropable" val="false" />
<set name="is_destroyable" val="false" />
<set name="is_sellable" val="false" />
<set name="default_action" val="PEEL" />
<set name="immediate_effect" val="true" />
<set name="material" val="PAPER" />
<set name="is_stackable" val="true" />
<set name="reuse_delay" val="86400000" /> <!-- 1 Day -->
<set name="handler" val="ExtractableItems" />
<capsuled_items>
<item id="60009" min="3" max="3" chance="100" /> <!-- Festival Fairy's Lucky Ticket -->
</capsuled_items>
</item>
<item id="60012" name="Barter Package" type="EtcItem">
<!-- Double-click to obtain rare items. -->

View File

@ -1103,8 +1103,41 @@
<skill id="27859" toLevel="1" name="Balthus Knights' Top-grade Mark">
<!-- Grants you a disguise for 2 h. You'll have a chance to receive special supplies. Acquired XP/ SP +50%. -->
<icon>icon.ev_balthus_token</icon>
<operateType>A1</operateType>
<itemConsumeCount>1</itemConsumeCount>
<itemConsumeId>28609</itemConsumeId>
<abnormalLevel>1</abnormalLevel>
<abnormalTime>7200</abnormalTime>
<abnormalType>CHANGEBODY</abnormalType>
<abnormalVisualEffect>CHANGESHAPE_TRANSFORM</abnormalVisualEffect>
<stayAfterDeath>true</stayAfterDeath>
<blockedInOlympiad>true</blockedInOlympiad>
<effectPoint>1</effectPoint>
<isMagic>4</isMagic> <!-- Magic Skill -->
<magicLevel>56</magicLevel>
<operateType>A2</operateType>
<reuseDelay>60000</reuseDelay>
<canBeDispelled>false</canBeDispelled>
<hitTime>500</hitTime>
<basicProperty>NONE</basicProperty>
<magicCriticalRate>5</magicCriticalRate>
<hitCancelTime>0</hitCancelTime>
<targetType>SELF</targetType>
<affectScope>SINGLE</affectScope>
<irreplacableBuff>true</irreplacableBuff>
<isNecessaryToggle>true</isNecessaryToggle>
<passiveConditions>
<condition name="CheckLevel">
<minLevel>85</minLevel>
</condition>
</passiveConditions>
<effects>
<effect name="ExpModify">
<amount>50</amount>
</effect>
<effect name="SpModify">
<amount>50</amount>
</effect>
</effects>
</skill>
<skill id="27860" toLevel="1" name="Royal R99-grade White Save Ticket - Armor">
<operateType>A1</operateType>

View File

@ -1969,7 +1969,74 @@
<skill id="29441" toLevel="1" name="Lucky Gift Coupon (1-hour)">
<!-- For $s1, PvE damage +10%, Attribute Resistance +20, acquired XP +10%. Allows to take part in the raffle. -->
<icon>icon.skill0000</icon>
<operateType>A1</operateType>
<itemConsumeCount>1</itemConsumeCount>
<itemConsumeId>60009</itemConsumeId>
<abnormalLevel>1</abnormalLevel>
<abnormalTime>3600</abnormalTime>
<abnormalType>CHANGEBODY</abnormalType>
<abnormalVisualEffect>CHANGESHAPE_TRANSFORM</abnormalVisualEffect>
<stayAfterDeath>true</stayAfterDeath>
<blockedInOlympiad>true</blockedInOlympiad>
<effectPoint>1</effectPoint>
<isMagic>4</isMagic> <!-- Magic Skill -->
<magicLevel>56</magicLevel>
<operateType>A2</operateType>
<reuseDelay>60000</reuseDelay>
<canBeDispelled>false</canBeDispelled>
<hitTime>500</hitTime>
<basicProperty>NONE</basicProperty>
<magicCriticalRate>5</magicCriticalRate>
<hitCancelTime>0</hitCancelTime>
<targetType>SELF</targetType>
<affectScope>SINGLE</affectScope>
<irreplacableBuff>true</irreplacableBuff>
<isNecessaryToggle>true</isNecessaryToggle>
<passiveConditions>
<condition name="CheckLevel">
<minLevel>85</minLevel>
</condition>
</passiveConditions>
<effects>
<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="DefenceAttribute">
<amount>20</amount>
<attribute>FIRE</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>WATER</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>EARTH</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>WIND</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>HOLY</attribute>
</effect>
<effect name="DefenceAttribute">
<amount>20</amount>
<attribute>DARK</attribute>
</effect>
<effect name="ExpModify">
<amount>10</amount>
</effect>
</effects>
</skill>
<skill id="29442" toLevel="1" name="Freya's Lucky Pouch">
<icon>icon.skill0000</icon>

View File

@ -47,10 +47,18 @@
<value level="4">icon.etc_lottery_card_i00</value>
<value level="5">icon.christmas_card_box2</value>
</icon>
<itemConsumeCount>1</itemConsumeCount>
<itemConsumeId>49784</itemConsumeId>
<abnormalLevel>1</abnormalLevel>
<abnormalTime>3600</abnormalTime>
<abnormalLevel>
<value level="1">1</value>
<value level="2">2</value>
<value level="3">3</value>
<value level="4">4</value>
</abnormalLevel>
<abnormalTime>
<value level="1">3600</value>
<value level="2">7200</value>
<value level="3">21600</value>
<value level="4">28800</value>
</abnormalTime>
<abnormalType>CHANGEBODY</abnormalType>
<abnormalVisualEffect>CHANGESHAPE_TRANSFORM</abnormalVisualEffect>
<stayAfterDeath>true</stayAfterDeath>
@ -67,6 +75,8 @@
<hitCancelTime>0</hitCancelTime>
<targetType>SELF</targetType>
<affectScope>SINGLE</affectScope>
<isNecessaryToggle>true</isNecessaryToggle>
<irreplacableBuff>true</irreplacableBuff>
<passiveConditions>
<condition name="CheckLevel">
<minLevel>85</minLevel>

View File

@ -0,0 +1,407 @@
/*
* 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.instancemanager.events;
import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.l2jmobius.commons.threads.ThreadPool;
import org.l2jmobius.commons.util.Chronos;
import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.commons.util.Rnd;
import org.l2jmobius.gameserver.enums.MailType;
import org.l2jmobius.gameserver.instancemanager.MailManager;
import org.l2jmobius.gameserver.model.Message;
import org.l2jmobius.gameserver.model.StatSet;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import org.l2jmobius.gameserver.model.holders.ItemHolder;
import org.l2jmobius.gameserver.model.item.instance.Item;
import org.l2jmobius.gameserver.model.itemcontainer.Mail;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEvent;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEventJackpotUser;
import org.l2jmobius.gameserver.util.Broadcast;
/**
* @author Index
*/
public class BalthusEventManager implements IXmlReader
{
protected static final Logger LOGGER = Logger.getLogger(BalthusEventManager.class.getName());
private final Set<Player> _players = ConcurrentHashMap.newKeySet();
private final Map<Integer, BalthusEventHolder> _templates = new HashMap<>();
private boolean _isEasyMode;
private ItemHolder _consolation;
private int _minimalLevel = 0;
private String _mailSubject = null;
private String _mailContent = null;
private boolean _isRunning = false;
private int _currProgress;
private int _currState;
private int _avoidMinutesIssue;
private Player _winner = null;
private ItemChanceHolder _rewardItem;
public void addPlayer(Player player)
{
_players.add(player);
}
public void removePlayer(Player player)
{
_players.remove(player);
}
public Set<Player> getPlayers()
{
return _players;
}
public void removeParticipant(Player player)
{
_players.remove(player);
}
public boolean isPlayerParticipant(Player player)
{
return _players.contains(player);
}
public int getMinimalLevel()
{
return _minimalLevel;
}
public int getCurrentProgress()
{
return _currProgress;
}
public int getCurrentState()
{
return _currState;
}
public ItemHolder getConsolation()
{
return _consolation;
}
public int getCurrRewardItem()
{
return _rewardItem.getId();
}
public boolean isRunning()
{
return _isRunning;
}
public int getTime()
{
return Calendar.getInstance().get(Calendar.MINUTE) * 60; // client makes 3600 - time
}
protected BalthusEventManager()
{
load();
final long currentTime = Chronos.currentTimeMillis();
final Calendar calendar = Calendar.getInstance();
final long hours = calendar.get(Calendar.HOUR_OF_DAY);
final long mins = calendar.get(Calendar.MINUTE);
long startDelay;
if (mins <= 11)
{
calendar.set(Calendar.MINUTE, 12);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 20;
_avoidMinutesIssue = 1;
}
else if (mins <= 23)
{
calendar.set(Calendar.MINUTE, 24);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 40;
_avoidMinutesIssue = 2;
}
else if (mins <= 35)
{
calendar.set(Calendar.MINUTE, 36);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 60;
_avoidMinutesIssue = 3;
}
else if (mins <= 47)
{
calendar.set(Calendar.MINUTE, 48);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 80;
_avoidMinutesIssue = 4;
}
else
{
calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + 1);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
startDelay = calendar.getTimeInMillis() - currentTime;
_currProgress = 100;
_avoidMinutesIssue = 5;
}
if (((hours > 11) && (hours < 23)) || (hours == 23))
{
_currState = (int) hours - 11;
}
else
{
_currState = (int) hours + 13;
}
getNewRewardItem();
ThreadPool.scheduleAtFixedRate(this::tryToGetWinner, startDelay, 720000);
}
@Override
public synchronized void load()
{
_templates.clear();
parseDatapackFile("data/scripts/events/BalthusFestival/rewards.xml");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _templates.size() + " rewards.");
}
@Override
public void parseDocument(Document doc, File f)
{
final AtomicInteger i = new AtomicInteger();
forEach(doc, "list", listNode ->
{
final StatSet set = new StatSet(parseAttributes(listNode));
if (_minimalLevel == 0)
{
_isEasyMode = set.getBoolean("easyMode", false);
_minimalLevel = set.getInt("minLevel", 85);
_consolation = new ItemHolder(set.getInt("id", 49783), set.getInt("count", 100));
_mailSubject = set.getString("mailSubject", "Balthus Knight Lottery");
_mailContent = set.getString("mailContent", "You win reward in Balthus Event!");
}
forEach(listNode, "reward", reward ->
{
final AtomicInteger j = new AtomicInteger();
final Map<Integer, Map<ItemChanceHolder, Double>> tempRewardList = new HashMap<>();
final Map<Integer, Integer> rewardTime = new HashMap<>();
final StatSet rewardSet = new StatSet(parseAttributes(reward));
rewardTime.put(rewardSet.getInt("from"), rewardSet.getInt("to", rewardSet.getInt("from")));
forEach(reward, "items", itemNode ->
{
forEach(itemNode, "item", item ->
{
final Map<ItemChanceHolder, Double> tempChanceRewardList = new HashMap<>();
j.getAndIncrement();
final StatSet itemSet = new StatSet(parseAttributes(item));
ItemChanceHolder itemChanceHolder = new ItemChanceHolder(itemSet.getInt("id", 57), itemSet.getDouble("chance", 100), itemSet.getInt("count", 100));
tempChanceRewardList.put(itemChanceHolder, itemSet.getDouble("lotteryChance", 0.0));
tempRewardList.put(j.intValue(), tempChanceRewardList);
});
i.getAndIncrement();
_templates.put(i.intValue(), new BalthusEventHolder(rewardTime, tempRewardList));
});
});
});
}
private void tryToGetWinner()
{
_avoidMinutesIssue++;
if (_isRunning && (_avoidMinutesIssue != 6))
{
return;
}
final int random = Rnd.get(100);
if (!_isRunning && (random >= _rewardItem.getChance()) && !_players.isEmpty())
{
final List<Player> playerList = new ArrayList<>(_players);
Collections.shuffle(playerList);
for (Player player : playerList)
{
if (player.getLevel() >= getMinimalLevel())
{
_winner = player;
}
}
if (_winner != null)
{
LOGGER.info(getClass().getSimpleName() + ": New winner for " + _currState + " of Balthus Event is " + _winner.getName() + " - " + _winner.getObjectId() + ". Player win " + new Item(_rewardItem.getId()).getItemName() + " - " + _rewardItem.getId() + " count: " + _rewardItem.getCount() + ".");
Broadcast.toAllOnlinePlayers(new ExBalthusEventJackpotUser());
Broadcast.toAllOnlinePlayers(new SystemMessage(SystemMessageId.S1_HAS_OBTAINED_S2_FROM_THE_FESTIVAL_FAIRY).addPcName(_winner).addItemName(_rewardItem.getId()));
_isRunning = true;
sendConsolationItemsToAll();
sendRewardToPlayer(_winner);
}
else
{
_currProgress += 20;
}
}
else
{
_currProgress += 20;
}
if (_avoidMinutesIssue == 6)
{
resetCurrentStage();
}
for (Player player : World.getInstance().getPlayers())
{
player.sendPacket(new ExBalthusEvent(player));
}
}
private void resetCurrentStage()
{
_currState += 1;
_winner = null;
if (_currState == 25)
{
_currState = 1;
}
_currProgress = 20;
if (!_isRunning && _isEasyMode)
{
sendConsolationItemsToAll();
}
_isRunning = false;
_rewardItem = null;
_avoidMinutesIssue = 1;
getNewRewardItem();
}
private void sendConsolationItemsToAll()
{
for (Player player : _players)
{
if (player == _winner)
{
continue;
}
player.getVariables().set(PlayerVariables.BALTHUS_REWARD, player.getVariables().getInt(PlayerVariables.BALTHUS_REWARD, 0) + _consolation.getCount());
player.sendPacket(new SystemMessage(SystemMessageId.YOU_VE_OBTAINED_S1_FAIRY_S_LUCKY_COINS).addInt((int) _consolation.getCount()));
}
}
private void getNewRewardItem()
{
while (_rewardItem == null)
{
for (BalthusEventHolder holder : _templates.values())
{
if (holder.getRewardTime() == null)
{
continue;
}
final Map<Integer, Integer> rewardTime = holder.getRewardTime();
final int firstParam = rewardTime.keySet().iterator().hasNext() ? rewardTime.keySet().iterator().next() : 0;
final Calendar calendar = Calendar.getInstance();
if ((firstParam <= calendar.get(Calendar.HOUR_OF_DAY)) && (calendar.get(Calendar.HOUR_OF_DAY) <= rewardTime.get(firstParam)))
{
final double random = Rnd.get(100d);
double chance = 0;
for (Map<ItemChanceHolder, Double> map : holder.getRewardList().values())
{
for (Entry<ItemChanceHolder, Double> entry : map.entrySet())
{
chance += entry.getValue();
if (chance >= random)
{
_rewardItem = entry.getKey();
LOGGER.info(getClass().getSimpleName() + ": Reward for " + _currState + " stage set. Next reward item is " + new Item(_rewardItem.getId()).getItemName() + " - " + _rewardItem.getId() + " count: " + _rewardItem.getCount() + ".");
break;
}
}
if (_rewardItem != null)
{
break;
}
}
}
}
}
}
private void sendRewardToPlayer(Player player)
{
final Message msg = new Message(player.getObjectId(), _mailSubject, _mailContent, MailType.NEWS_INFORMER);
final Mail attachments = msg.createAttachments();
attachments.addItem("Balthus Knight Lottery", _rewardItem.getId(), _rewardItem.getCount(), null, null);
MailManager.getInstance().sendMessage(msg);
}
public static class BalthusEventHolder
{
// From hour to hour.
private final Map<Integer, Integer> _rewardTime;
// Time reward - Reward item, chance to put in lottery.
private final Map<Integer, Map<ItemChanceHolder, Double>> _rewardList;
public BalthusEventHolder(Map<Integer, Integer> rewardTime, Map<Integer, Map<ItemChanceHolder, Double>> rewardList)
{
_rewardTime = rewardTime;
_rewardList = rewardList;
}
public Map<Integer, Integer> getRewardTime()
{
return _rewardTime;
}
public Map<Integer, Map<ItemChanceHolder, Double>> getRewardList()
{
return _rewardList;
}
}
public static BalthusEventManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final BalthusEventManager INSTANCE = new BalthusEventManager();
}
}

View File

@ -63,6 +63,7 @@ public class PlayerVariables extends AbstractVariables
public static final String CLAN_CONTRIBUTION = "CLAN_CONTRIBUTION";
public static final String CLAN_CONTRIBUTION_TOTAL = "CLAN_CONTRIBUTION_TOTAL";
public static final String CLAN_CONTRIBUTION_REWARDED = "CLAN_CONTRIBUTION_REWARDED";
public static final String BALTHUS_REWARD = "BALTHUS_REWARD";
public static final String AUTO_USE_SETTINGS = "AUTO_USE_SETTINGS";
public static final String AUTO_USE_SHORTCUTS = "AUTO_USE_SHORTCUTS";
public static final String HUNTING_ZONE_ENTRY = "HUNTING_ZONE_ENTRY_";

View File

@ -48,6 +48,7 @@ import org.l2jmobius.gameserver.network.clientpackets.attributechange.SendChange
import org.l2jmobius.gameserver.network.clientpackets.autoplay.ExAutoPlaySetting;
import org.l2jmobius.gameserver.network.clientpackets.autoplay.ExRequestActivateAutoShortcut;
import org.l2jmobius.gameserver.network.clientpackets.awakening.RequestCallToChangeClass;
import org.l2jmobius.gameserver.network.clientpackets.balthusevent.RequestEventBalthusToken;
import org.l2jmobius.gameserver.network.clientpackets.ceremonyofchaos.RequestCancelCuriousHouse;
import org.l2jmobius.gameserver.network.clientpackets.ceremonyofchaos.RequestCuriousHouseHtml;
import org.l2jmobius.gameserver.network.clientpackets.ceremonyofchaos.RequestJoinCuriousHouse;
@ -455,7 +456,7 @@ public enum ExIncomingPackets implements IIncomingPackets<GameClient>
REQUEST_CHECK_AGIT_DECO_AVAILABILITY(0x117, null, ConnectionState.IN_GAME),
REQUEST_USER_FACTION_INFO(0x118, RequestUserFactionInfo::new, ConnectionState.IN_GAME),
EX_EXIT_ARENA(0x119, null, ConnectionState.IN_GAME),
REQUEST_EVENT_BALTHUS_TOKEN(0x11A, null, ConnectionState.IN_GAME),
REQUEST_EVENT_BALTHUS_TOKEN(0x11A, RequestEventBalthusToken::new, ConnectionState.IN_GAME),
REQUEST_PARTY_MATCHING_HISTORY(0x11B, null, ConnectionState.IN_GAME),
EX_ARENA_CUSTOM_NOTIFICATION(0x11C, null, ConnectionState.IN_GAME),
REQUEST_TODO_LIST(0x11D, null, ConnectionState.IN_GAME),

View File

@ -0,0 +1,63 @@
/*
* 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.balthusevent;
import org.l2jmobius.commons.network.PacketReader;
import org.l2jmobius.gameserver.instancemanager.events.BalthusEventManager;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.clientpackets.IClientIncomingPacket;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.network.serverpackets.balthusevent.ExBalthusEvent;
/**
* @author Index
*/
public class RequestEventBalthusToken implements IClientIncomingPacket
{
@Override
public boolean read(GameClient client, PacketReader packet)
{
return true;
}
@Override
public void run(GameClient client)
{
final Player player = client.getPlayer();
if (player == null)
{
return;
}
final int count = player.getVariables().getInt(PlayerVariables.BALTHUS_REWARD, 0);
if (count != 0)
{
if (player.addItem("Balthus Consolation Item", BalthusEventManager.getInstance().getConsolation().getId(), count, player, true) != null)
{
player.getVariables().set(PlayerVariables.BALTHUS_REWARD, 0);
player.sendPacket(new ExBalthusEvent(player));
}
}
else
{
player.sendPacket(new SystemMessage(SystemMessageId.NO_FAIRY_S_LUCKY_COINS_AVAILABLE));
}
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.balthusevent;
import org.l2jmobius.commons.network.PacketWriter;
import org.l2jmobius.gameserver.instancemanager.events.BalthusEventManager;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.variables.PlayerVariables;
import org.l2jmobius.gameserver.network.OutgoingPackets;
import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
/**
* Consolation prize changing in SysTextures/ui6.ugx file "RewardClip.as" -> configUI -> this.tokenItemID = 49783;
* @author Index
*/
public class ExBalthusEvent implements IClientOutgoingPacket
{
private final Player _player;
public ExBalthusEvent(Player player)
{
_player = player;
}
@Override
public boolean write(PacketWriter packet)
{
OutgoingPackets.EX_BALTHUS_EVENT.writeId(packet);
packet.writeD(BalthusEventManager.getInstance().getCurrentState()); // CurrentState (max 24, because 1 state going 1 hour)
packet.writeD(BalthusEventManager.getInstance().getCurrentProgress()); // Progress
packet.writeD(BalthusEventManager.getInstance().getCurrRewardItem()); // CurrentRewardItem (current event item, what can be rewarded)
packet.writeD(_player.getVariables().getInt(PlayerVariables.BALTHUS_REWARD, 0)); // RewardTokenCount (current items for withdraw (available rewards))
packet.writeD((int) BalthusEventManager.getInstance().getConsolation().getCount()); // CurrentTokenCount (current count of "consolation prize")
packet.writeD(BalthusEventManager.getInstance().isPlayerParticipant(_player) ? 1 : 0); // Participated (player in event?)
packet.writeC(BalthusEventManager.getInstance().isRunning() ? 0 : 1); // Running (0 - already someone get this reward ? / 1 - item can be rewarded)
packet.writeD(BalthusEventManager.getInstance().getTime()); // Time (in seconds)
return true;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.balthusevent;
import org.l2jmobius.commons.network.PacketWriter;
import org.l2jmobius.gameserver.network.OutgoingPackets;
import org.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
/**
* @author Index
*/
public class ExBalthusEventJackpotUser implements IClientOutgoingPacket
{
public static final ExBalthusEventJackpotUser STATIC_PACKET = new ExBalthusEventJackpotUser();
@Override
public boolean write(PacketWriter packet)
{
OutgoingPackets.EX_BALTHUS_EVENT_JACKPOT_USER.writeId(packet);
return true;
}
}