- Хроники
- Chaotic Throne: High Five
- Homunculus
- Исходники
- Присутствуют
- Сборка
- OverWorld
Пример реализации простенького эвента для Хэллоуина под сервера на базе овера.
Хотя сразу скажу что без правок и доработок на овере это не заработает, т.к. у меня сервер уже во многом отличается от оригинального овера.
Но именно как пример и заготовка для написания своего с подобной идеей - подойдет вполне.
Сам эвент этот у меня в основе своей писался еще во времена ХФ и использует в целом все из того что там есть в виде кастомных копий - нпс/скилл.
---
Если активен эвент, то при убийстве мобов с определенным шансом выдается на экран уведомление и спавнится ненадолго нпс, слушающий в определенном радиусе от себя обычный чат и чат крика.
Первые 5 игроков, что успеют в чате произнести "trick or treat" или "шутка или угощение", будут перемещены этим нпс в эвентовый инстанс, где после общения с нпс там, будут превращены в оборотня и им будет дано 5 минут на убийство кроликов в этом инстансе. Наградой является дроп с этих кроликов.
---
Собственно код эвента и все такое
Уточню еще насчет параметра "ignore_penalty" в параметрах кроликов из инстанса - у меня он отключает штрафы от разницы уровней на награды с моба, т.е. разрешает даже высокоуровневому игроку нормально получать дроп с моба 1 уровня. Если у вас в сборке такой возможности нет - проще всего будет просто для кроликов написать отдельное AI, где и выдавать награду за их убийство.
Хотя сразу скажу что без правок и доработок на овере это не заработает, т.к. у меня сервер уже во многом отличается от оригинального овера.
Но именно как пример и заготовка для написания своего с подобной идеей - подойдет вполне.
Сам эвент этот у меня в основе своей писался еще во времена ХФ и использует в целом все из того что там есть в виде кастомных копий - нпс/скилл.
---
Если активен эвент, то при убийстве мобов с определенным шансом выдается на экран уведомление и спавнится ненадолго нпс, слушающий в определенном радиусе от себя обычный чат и чат крика.
Первые 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, где и выдавать награду за их убийство.
Последнее редактирование:






























