Простой эвент для Хэллоуина :)

Gaikotsu

яжпрограммист
Легенда
Легенда Истоков
Победитель в номинации 2024
Победитель в номинации 2023
Победитель в номинации 2022
Победитель в номинации 2021
Участник Новогоднего Фонда 2021
Эксперт
Знаток
Просветитель
Магистр реакций
Знаток письма
Куратор Данных
Медаль Благодарности
Старожил II степени
Старожил I степени
Победитель в номинации 2020
Победитель в номинации 2019
Клиент разработчик
Преподаватель
За веру и верность форуму
Победитель в номинации 2018
Медаль за активность на Форуме
За заслуги перед форумом
Web разработчик
Разработчик
За знание датапака
За знание ядра
Сообщения
2 151
Розыгрыши
0
Решения
36
Репутация
6 401
Реакции
3 347
Баллы
2 363
Хроники
  1. Chaotic Throne: High Five
  2. Homunculus
Исходники
Присутствуют
Сборка
OverWorld
Пример реализации простенького эвента для Хэллоуина под сервера на базе овера.
Хотя сразу скажу что без правок и доработок на овере это не заработает, т.к. у меня сервер уже во многом отличается от оригинального овера.
Но именно как пример и заготовка для написания своего с подобной идеей - подойдет вполне.
Сам эвент этот у меня в основе своей писался еще во времена ХФ и использует в целом все из того что там есть в виде кастомных копий - нпс/скилл.

---
Если активен эвент, то при убийстве мобов с определенным шансом выдается на экран уведомление и спавнится ненадолго нпс, слушающий в определенном радиусе от себя обычный чат и чат крика.
Первые 5 игроков, что успеют в чате произнести "trick or treat" или "шутка или угощение", будут перемещены этим нпс в эвентовый инстанс, где после общения с нпс там, будут превращены в оборотня и им будет дано 5 минут на убийство кроликов в этом инстансе. Наградой является дроп с этих кроликов.

---
Собственно код эвента и все такое
Java:
package events.TrickOrTreat;

import org.apache.commons.lang3.StringUtils;

import events.base.instances.FunEventInstance;
import l2p.commons.util.Rnd;
import l2p.gameserver.data.holder.SkillDataHolder;
import l2p.gameserver.enums.ScreenMessageAlign;
import l2p.gameserver.enums.summons.MountType;
import l2p.gameserver.managers.ReflectionManager;
import l2p.gameserver.model.Creature;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.entity.Reflection;
import l2p.gameserver.model.instances.NpcInstance;
import l2p.gameserver.model.skills.Skill;
import l2p.gameserver.model.world.World;
import l2p.gameserver.network.components.SystemMsg;
import l2p.gameserver.network.s2c.ExShowScreenMessage;
import l2p.gameserver.utils.NpcUtils;
import l2p.gameserver.utils.PositionUtils;

/**
 * @author Gaikotsu
 */
public class TrickOrTreat extends FunEventInstance
{
    private static final int Elpy = 60001;
    private static final int ElpySpawnChance = 1_000;
    private static final int InstanceId = 9002;

    private static final Skill TransformSkill = SkillDataHolder.getInstance().getSkill(150001, 1);

    public TrickOrTreat()
    {
        super("Trick or Treat", "Шутка или угощение", StringUtils.EMPTY);

        addCommand("startEventGame");
    }

    public static TrickOrTreat getInstance()
    {
        return SingletonHolder._instance;
    }

    @Override
    public void onLoad()
    {
        getInstance().onLoad(true);
    }

    @Override
    public void onDeath(Creature killed, Creature killer)
    {
        if (Rnd.get(1_000_000) <= ElpySpawnChance && NpcUtils.isDropAllowed(killed, killer) && killer.getReflection() == ReflectionManager.DEFAULT)
        {
            broadcastPacket(World.getAroundPlayers(killed, 3000, 1000), new ExShowScreenMessage("Поблизости появился загадочный кролик. Найдите его.\nНайдя, скажите или крикните в чат 'Trick or Treat' или 'шутка или угощение'.\nЕсли повезет, то вам предоставится возможность сыграть в небольшую игру.", 10000, ScreenMessageAlign.BOTTOM_RIGHT));
            NpcUtils.spawn(Elpy, PositionUtils.findAroundPosition(killed, 50, 200));
        }
    }

    @Override
    public void onBypassFeedback(NpcInstance npc, Player player, String command, String[] params)
    {
        if (command.equalsIgnoreCase("startEventGame"))
        {
            if (!player.checkNextActionUseTime("werewolfTransformation", 5000))
                return;

            Reflection r = npc.getReflection();

            if (r.getInstantZoneId() != InstanceId)
                return;

            if (player.getTransformation() != 0)
            {
                player.sendPacket(SystemMsg.YOU_ALREADY_POLYMORPHED_AND_CANNOT_POLYMORPH_AGAIN);
                return;
            }

            if (player.getMount().isRiding() || player.getMount().getType() != MountType.NONE)
            {
                player.sendPacket(SystemMsg.YOU_CANNOT_POLYMORPH_WHILE_RIDING_A_PET);
                return;
            }

            if (player.isBlockBuff(TransformSkill) || player.isBlockDebuff(TransformSkill) || player.getStats().isAbnormalShield(false))
            {
                player.sendPacket(SystemMsg.YOU_CANNOT_POLYMORPH_WHILE_UNDER_THE_EFFECT_OF_A_SPECIAL_SKILL);
                return;
            }

            if (player.getSummonList().getPet() != null || player.getSummonList().getSummonCount() > 0)
            {
                player.sendPacket(SystemMsg.YOU_CANNOT_POLYMORPH_WHEN_YOU_HAVE_SUMMONED_A_SERVITOR_OR_PET);
                return;
            }

            if (TransformSkill.checkCondition(player, player, null, false, false, true, true))
            {
                player.getAI().intentionCast(player, TransformSkill, null);
                r.spawnByGroup("event_trick_or_treat_2");
                r.startCollapseTimer(5 * 60 * 1000L);
                npc.startDeleteTask(500L);
            }
        }
    }

    private static class SingletonHolder
    {
        private static final TrickOrTreat _instance = new TrickOrTreat();
    }
}
Java:
package ai.events.TrickOrTreat;

import java.util.concurrent.atomic.AtomicInteger;

import l2p.gameserver.ai.DefaultAI;
import l2p.gameserver.enums.ChatType;
import l2p.gameserver.listener.actor.player.OnChatListener;
import l2p.gameserver.model.Creature;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.actor.listener.PlayerListenerList;
import l2p.gameserver.model.instances.NpcInstance;
import l2p.gameserver.model.skills.Skill;
import l2p.gameserver.utils.NpcUtils;
import l2p.gameserver.utils.ReflectionUtils;

/**
 * @author Gaikotsu
 */
public class ElpyNpc extends DefaultAI
{
    private static final int _instanceId = 9002;

    private ChatListener _chatListener = new ChatListener();
    private AtomicInteger _counter = new AtomicInteger(0);

    public ElpyNpc(NpcInstance actor)
    {
        super(actor);
    }

    @Override
    public void onEvtSpawn()
    {
        super.onEvtSpawn();

        PlayerListenerList.addGlobal(_chatListener);
        _counter.set(0);
        addTimer(666, 30 * 1000L);
    }

    @Override
    public void onEvtDead(Creature killer)
    {
        super.onEvtDead(killer);

        PlayerListenerList.removeGlobal(_chatListener);
    }

    @Override
    protected void onEvtTimer(int timerId, Object arg1, Object arg2)
    {
        NpcInstance actor = getActor();

        if (actor == null || actor.isDead())
            return;

        if (timerId == 666)
            suicide();
    }

    @Override
    protected void onEvtAttacked(Creature attacker, int damage, Skill attackerSkill)
    {}

    @Override
    public boolean checkAggression(NpcInstance actor, Creature target)
    {
        return false;
    }

    @Override
    protected void onEvtAggression(Creature target, int aggro)
    {}

    private class ChatListener implements OnChatListener
    {
        @Override
        public void onSay(Player player, String msg, ChatType type)
        {
            if (_counter.get() >= 3)
                return;

            NpcInstance elpy = NpcUtils.getNearbyNpc(player, 3000, 60001);

            if (elpy == null || elpy.isDead() || msg == null || player == null || player.isDead())
                return;

            if (type == ChatType.ALL || type == ChatType.SHOUT)
            {
                if (!msg.toLowerCase().contains("trick or treat") && !msg.toLowerCase().contains("шутка или угощение"))
                    return;

                if (!player.getInstances().canEnter(_instanceId))
                    return;

                if (_counter.incrementAndGet() >= 5)
                    elpy.doDie(null);

                ReflectionUtils.enterReflection(player, _instanceId);
            }
        }
    }
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE list SYSTEM "instances.dtd">
<list>
    <instance id="9002" name="Event Zone - Trick or Treat">
        <params>
            <param name="levels" value="1;130" />
            <param name="players" value="1;1" />
            <param name="timeLimit" value="15" />
            <param name="maxChannels" value="100" />
            <param name="collapseIfEmpty" value="0" />
            <param name="resetReuse" value="* * * * *" />
            <param name="setReuseUponEntry" value="false" />
            <param name="sharedReuseGroup" value="0" />
        </params>
        <teleport loc="-114680 248500 -7870" />
        <spawns>
            <group name="event_trick_or_treat_1" spawned="true" />
            <group name="event_trick_or_treat_2" spawned="false" />
        </spawns>
    </instance>
</list>

<!-- -------------------------- -->

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE list SYSTEM "../spawn_data.dtd">
<list>
    <spawn group="event_trick_or_treat_1">
        <npc id="60002" count="1" respawn="60" />    <!-- Сфера -->
        <point x="-114180" y="248700" z="-7870" />
    </spawn>
    <spawn group="event_trick_or_treat_2">
        <npc id="60003" count="25" respawn="15" />    <!-- Беззаботный Кролик -->
        <territory>
            <add x="-114040" y="247624" zmin="-7918" zmax="-7718" />
            <add x="-115320" y="247784" zmin="-7918" zmax="-7718" />
            <add x="-115224" y="248424" zmin="-7918" zmax="-7718" />
            <add x="-114808" y="248840" zmin="-7918" zmax="-7718" />
            <add x="-114120" y="248664" zmin="-7918" zmax="-7718" />
            <add x="-113864" y="248184" zmin="-7918" zmax="-7718" />
            <banned_territory>
                <add x="-114104" y="247864" zmin="-7918" zmax="-7718" />
                <add x="-114088" y="248280" zmin="-7918" zmax="-7718" />
                <add x="-114456" y="248248" zmin="-7918" zmax="-7718" />
                <add x="-114472" y="247912" zmin="-7918" zmax="-7718" />
            </banned_territory>
        </territory>
    </spawn>
</list>
XML:
    <!-- Загадочный Кролик -->
    <npc id="60001" name="Загадочный Кролик" title="" pts_name="none">
        <stat name="type" value="Npc" />
        <stat name="ai" value="events.TrickOrTreat.ElpyNpc" />
        <stat name="level" value="99" />
        <stat name="race" value="animal" />
        <stat name="sex" value="male" />
        <stat name="collision_height" value="12.0;12.0" />
        <stat name="collision_radius" value="12.0;12.0" />
        <stat name="str" value="89" />
        <stat name="con" value="82" />
        <stat name="dex" value="55" />
        <stat name="int" value="79" />
        <stat name="wit" value="78" />
        <stat name="men" value="78" />
        <stat name="luc" value="34" />
        <stat name="cha" value="40" />
        <stat name="org_hp" value="6696028" />    <!-- 11,584,128 -->
        <stat name="org_mp" value="2355" />    <!-- 3,568 -->
        <stat name="org_hp_regen" value="8.5" />
        <stat name="org_mp_regen" value="3" />
        <stat name="ground_high" value="180;0;0" />
        <stat name="ground_low" value="50;0;0" />
        <stat name="base_physical_attack" value="1949.95411856464" />    <!-- 5,008 -->
        <stat name="base_physical_defend" value="405.66735" />    <!-- 763 -->
        <stat name="base_magic_attack" value="1331.56588332443" />    <!-- 7,567 -->
        <stat name="base_magic_defend" value="296.84976" />    <!-- 845 -->
        <stat name="base_attack_range" value="40" />
        <stat name="base_attack_type" value="sword" />
        <stat name="base_attack_speed" value="253" />    <!-- 300 -->
        <stat name="base_critical" value="40" />
        <stat name="base_rand_dam" value="10" />
        <stat name="base_attribute_attack" value="none;0" />
        <stat name="base_attribute_defend" value="0;0;0;0;0;0;0" />
        <stat name="ex_crt_effect" value="true" />
        <stat name="physical_hit_modify" value="5" />
        <stat name="agro_range" value="0" />
        <ai_params>
            <set name="targetable" value="false" />
            <set name="show_html" value="false" />
        </ai_params>
    </npc>
    <!-- Сфера -->
    <npc id="60002" name="Сфера" title="" pts_name="none">
        <stat name="type" value="Npc" />
        <stat name="ai" value="CharacterAI" />
        <stat name="level" value="99" />
        <stat name="race" value="etc" />
        <stat name="sex" value="etc" />
        <stat name="collision_height" value="30.0;30.0" />
        <stat name="collision_radius" value="10.0;10.0" />
        <stat name="str" value="89" />
        <stat name="con" value="82" />
        <stat name="dex" value="55" />
        <stat name="int" value="79" />
        <stat name="wit" value="78" />
        <stat name="men" value="78" />
        <stat name="luc" value="34" />
        <stat name="cha" value="40" />
        <stat name="org_hp" value="8446" />    <!-- 14,612 -->
        <stat name="org_mp" value="2355" />    <!-- 3,568 -->
        <stat name="org_hp_regen" value="8.5" />
        <stat name="org_mp_regen" value="3" />
        <stat name="ground_high" value="1;0;0" />
        <stat name="ground_low" value="1;0;0" />
        <stat name="base_physical_attack" value="1949.95411856464" />    <!-- 5,008 -->
        <stat name="base_physical_defend" value="405.66735" />    <!-- 763 -->
        <stat name="base_magic_attack" value="1331.56588332443" />    <!-- 7,567 -->
        <stat name="base_magic_defend" value="296.84976" />    <!-- 845 -->
        <stat name="base_attack_range" value="40" />
        <stat name="base_attack_type" value="sword" />
        <stat name="base_attack_speed" value="253" />    <!-- 300 -->
        <stat name="base_critical" value="40" />
        <stat name="base_rand_dam" value="10" />
        <stat name="base_attribute_attack" value="none;0" />
        <stat name="base_attribute_defend" value="0;0;0;0;0;0;0" />
        <stat name="ex_crt_effect" value="true" />
        <stat name="physical_hit_modify" value="5" />
        <stat name="agro_range" value="0" />
        <ai_params>
            <set name="show_name" value="false" />
            <set name="show_info" value="false" />
        </ai_params>
    </npc>
    <!-- Беззаботный Кролик -->
    <npc id="60003" name="Беззаботный Кролик" title="" pts_name="none">
        <stat name="type" value="Monster" />
        <stat name="ai" value="Elpy" />
        <stat name="level" value="1" />
        <stat name="race" value="animal" />
        <stat name="sex" value="male" />
        <stat name="collision_height" value="12.0;12.0" />
        <stat name="collision_radius" value="12.0;12.0" />
        <stat name="str" value="88" />
        <stat name="con" value="82" />
        <stat name="dex" value="55" />
        <stat name="int" value="79" />
        <stat name="wit" value="78" />
        <stat name="men" value="78" />
        <stat name="luc" value="34" />
        <stat name="cha" value="40" />
        <stat name="org_hp" value="39" />    <!-- 67 -->
        <stat name="org_mp" value="40" />    <!-- 61 -->
        <stat name="org_hp_regen" value="2" />
        <stat name="org_mp_regen" value="0.9" />
        <stat name="ground_high" value="180;0;0" />
        <stat name="ground_low" value="50;0;0" />
        <stat name="base_physical_attack" value="8.47458" />    <!-- 10 -->
        <stat name="base_physical_defend" value="44.44444" />    <!-- 40 -->
        <stat name="base_magic_attack" value="5.78704" />    <!-- 8 -->
        <stat name="base_magic_defend" value="32.52252" />    <!-- 44 -->
        <stat name="base_attack_range" value="40" />
        <stat name="base_attack_type" value="sword" />
        <stat name="base_attack_speed" value="253" />    <!-- 300 -->
        <stat name="base_critical" value="40" />
        <stat name="base_rand_dam" value="10" />
        <stat name="base_attribute_attack" value="none;0" />
        <stat name="base_attribute_defend" value="0;0;0;0;0;0;0" />
        <stat name="ex_crt_effect" value="true" />
        <stat name="physical_hit_modify" value="5" />
        <stat name="agro_range" value="0" />
        <ai_params>
            <set name="ignore_penalty" value="true" />
        </ai_params>
    </npc>
Код:
NpcGrp:

npc_begin    npc_id=60001    class_name=[LineageNpc2.br_Event_Rabbit]    mesh_name=[branch2.ev_rabbit_boss_m00]    texture_name={[Branchsys2.npc.ev_rabbit_boss]}    texture_name_second={}    property_list={4416;4}    npc_speed=2.25    attack_sound1={}    defense_sound1={[MonSound.Hit_Normal_10];[MonSound.Hit_normal_3];[MonSound.Hit_Wet_1];[MonSound.Hit_Bone_2]}    damage_sound={[MonSound.rabbit_dmg_1];[MonSound.rabbit_dmg_2];[MonSound.rabbit_dmg_3]}    deco_effect={}    quest={}    attack_effect=[LineageEffect.p_u002_a]    sound_radius=50    sound_vol=250    sound_random=30    social=0    hpshowable=1    dialog_sound={}    use_zoomincam=0    summon_sort=0    summon_max_count=0    summon_grade=0    drawscale=-1.0    sound_priority=0.0    npc_icon_name=[None]    Silhouette=0    ground_high=180    ground_low=50    collision_radius=12.0    collision_radius_2=12.0    collision_height=12.0    collision_height_2=12.0    slot_rhand=0    slot_lhand=0    slot_chest=0    org_hp=601.26582278481    org_mp=1846.8    npc_type=-1    npc_end
npc_begin    npc_id=60002    class_name=[LineageNpcEV.light_burst_big]    mesh_name=[LineageNpcsEV.collision_dummy]    texture_name={[DropItemsTex.clear_npc_t00];[DropItemsTex.clear_npc_t00];[DropItemsTex.clear_npc_t00];[DropItemsTex.clear_npc_t00]}    texture_name_second={}    property_list={4416;2}    npc_speed=1.0    attack_sound1={}    defense_sound1={[MonSound.Hit_normal_3];[MonSound.Hit_Wet_1];[MonSound.Hit_Bone_2];[MonSound.Hit_normal_12]}    damage_sound={}    deco_effect={}    quest={}    attack_effect=[LineageEffect.p_u002_a]    sound_radius=50    sound_vol=250    sound_random=30    social=0    hpshowable=1    dialog_sound={}    use_zoomincam=0    summon_sort=0    summon_max_count=0    summon_grade=0    drawscale=-1.0    sound_priority=0.0    npc_icon_name=[None]    Silhouette=0    ground_high=1    ground_low=1    collision_radius=10.0    collision_radius_2=10.0    collision_height=30.0    collision_height_2=30.0    slot_rhand=0    slot_lhand=0    slot_chest=0    org_hp=278980.929339731    org_mp=18468.0    npc_type=-1    npc_end
npc_begin    npc_id=60003    class_name=[LineageNpc2.br_Event_Rabbit]    mesh_name=[branch2.ev_rabbit_boss_m00]    texture_name={[Branchsys2.npc.ev_rabbit_boss]}    texture_name_second={}    property_list={4416;4}    npc_speed=2.25    attack_sound1={}    defense_sound1={[MonSound.Hit_Normal_10];[MonSound.Hit_normal_3];[MonSound.Hit_Wet_1];[MonSound.Hit_Bone_2]}    damage_sound={[MonSound.rabbit_dmg_1];[MonSound.rabbit_dmg_2];[MonSound.rabbit_dmg_3]}    deco_effect={}    quest={}    attack_effect=[LineageEffect.p_u002_a]    sound_radius=50    sound_vol=250    sound_random=30    social=0    hpshowable=1    dialog_sound={}    use_zoomincam=0    summon_sort=0    summon_max_count=0    summon_grade=0    drawscale=-1.0    sound_priority=0.0    npc_icon_name=[None]    Silhouette=0    ground_high=180    ground_low=50    collision_radius=12.0    collision_radius_2=12.0    collision_height=12.0    collision_height_2=12.0    slot_rhand=0    slot_lhand=0    slot_chest=0    org_hp=601.26582278481    org_mp=1846.8    npc_type=-1    npc_end

NpcName:
npc_begin    id=60001    name=[Загадочный Кролик]    nick=[]    nickcolor=9CE8A9FF    npc_end
npc_begin    id=60002    name=[Сфера]    nick=[]    nickcolor=9CE8A9FF    npc_end
npc_begin    id=60003    name=[Беззаботный Кролик]    nick=[]    nickcolor=9CE8A9FF    npc_end
XML:
<!-- Трансформация Трейкхана -->
    <skill id="150001" levels="1" name="Трансформация Трейкхана" pts_name="none">
        <!-- Перевоплощает в Трейкхана. -->
        <stat name="icon" value="icon.skilltransform1" />
        <stat name="magic_type" value="physic" />
        <stat name="special_level" value="-1" />
        <stat name="target" value="self" />
        <stat name="skill_type" value="buff" />
        <stat name="operate_type" value="A2" />
        <stat name="abnormal_type" value="transform" />
        <stat name="abnormal_level" value="1" />
        <stat name="abnormal_time" value="310" />
        <stat name="next_action" value="none" />
        <stat name="irreplaceable" value="true" />
        <cond>
            <player can_transform="" />
        </cond>
        <for>
            <effect name="i_dispel_by_slot" params="(@dispel_before_tf);-1" />
            <effect name="i_target_cancel" />
            <effect name="p_transform" params="126">
                <set order="0x80" stat="p_physical_attack" value="50" />
                <set order="0x80" stat="p_magical_attack" value="25" />
                <set order="0x80" stat="p_physical_defence" value="1" />
                <set order="0x80" stat="p_magical_defence" value="1" />
            </effect>
        </for>
    </skill>
Код:
SkillGrp:
skill_begin    skill_id=150001    skill_level=1    skill_sublevel=0    icon_type=7    MagicType=0    operate_type=1    mp_consume=0    cast_range=-1    cast_style=0    hit_time=0.0    cool_time=0.0    reuse_delay=0.0    effect_point=1    is_magic=1    origin_skill=0    is_double=0    animation={[None]}    skill_visual_effect=[6649]    icon=[icon.skilltransform1]    icon_panel=[None]    debuff=0    resist_cast=0    enchant_skill_level=0    enchant_icon=[None]    hp_consume=0    rumble_self=-1    rumble_target=-1    skill_end

SkillName:
skill_begin    skill_id=150001    skill_level=1    skill_sublevel=0    name=[Трансформация Трейкхана]    desc=[Перевоплощает в Трейкхана.]    desc_param=[]    enchant_name=[]    enchant_name_param=[]    enchant_desc=[]    enchant_desc_param=[]    skill_end
HTML:
Вы попали в это место неспроста, Вам был предоставлен шанс сыграть в небольшой игре.

Как только будете готовы - скажите об этом мне и будете на время превращены в чудовище. В то же время поблизости появится очень много кроликов.

У Вас будет несколько минут на то, чтобы убить их как можно больше и собрать с них награды.

Как только время истечет - Вы будете отправлены обратно на то место, откуда Вас сюда перенесло.

[npc_%objectId%_startEventGame|Начать игру]

Уточню еще насчет параметра "ignore_penalty" в параметрах кроликов из инстанса - у меня он отключает штрафы от разницы уровней на награды с моба, т.е. разрешает даже высокоуровневому игроку нормально получать дроп с моба 1 уровня. Если у вас в сборке такой возможности нет - проще всего будет просто для кроликов написать отдельное AI, где и выдавать награду за их убийство.

 
Последнее редактирование:

Назад
Сверху