Free version update 14-12-2023.

This commit is contained in:
MobiusDevelopment
2023-12-14 02:11:28 +02:00
parent 6a0a4be1ea
commit 1204ad8e00
6352 changed files with 98838 additions and 68045 deletions

View File

@@ -614,6 +614,7 @@ public class Config
public static boolean ENABLE_AUTO_SKILL;
public static boolean ENABLE_AUTO_ITEM;
public static boolean RESUME_AUTO_PLAY;
public static boolean ENABLE_AUTO_ASSIST;
// --------------------------------------------------
// FloodProtector Settings
@@ -1355,6 +1356,7 @@ public class Config
public static boolean FAKE_PLAYER_USE_SHOTS;
public static boolean FAKE_PLAYER_KILL_PVP;
public static boolean FAKE_PLAYER_KILL_KARMA;
public static boolean FAKE_PLAYER_AUTO_ATTACKABLE;
public static boolean FAKE_PLAYER_AGGRO_MONSTERS;
public static boolean FAKE_PLAYER_AGGRO_PLAYERS;
public static boolean FAKE_PLAYER_AGGRO_FPC;
@@ -2241,6 +2243,7 @@ public class Config
ENABLE_AUTO_SKILL = generalConfig.getBoolean("EnableAutoSkill", true);
ENABLE_AUTO_ITEM = generalConfig.getBoolean("EnableAutoItem", true);
RESUME_AUTO_PLAY = generalConfig.getBoolean("ResumeAutoPlay", false);
ENABLE_AUTO_ASSIST = generalConfig.getBoolean("AssistLeader", false);
// Load FloodProtector config file
final PropertiesParser floodProtectorConfig = new PropertiesParser(FLOOD_PROTECTOR_CONFIG_FILE);
@@ -3416,6 +3419,7 @@ public class Config
FAKE_PLAYER_USE_SHOTS = fakePlayerConfig.getBoolean("FakePlayerUseShots", false);
FAKE_PLAYER_KILL_PVP = fakePlayerConfig.getBoolean("FakePlayerKillsRewardPvP", false);
FAKE_PLAYER_KILL_KARMA = fakePlayerConfig.getBoolean("FakePlayerUnflaggedKillsKarma", false);
FAKE_PLAYER_AUTO_ATTACKABLE = fakePlayerConfig.getBoolean("FakePlayerAutoAttackable", false);
FAKE_PLAYER_AGGRO_MONSTERS = fakePlayerConfig.getBoolean("FakePlayerAggroMonsters", false);
FAKE_PLAYER_AGGRO_PLAYERS = fakePlayerConfig.getBoolean("FakePlayerAggroPlayers", false);
FAKE_PLAYER_AGGRO_FPC = fakePlayerConfig.getBoolean("FakePlayerAggroFPC", false);

View File

@@ -27,6 +27,7 @@ import org.l2jmobius.commons.util.Rnd;
import org.l2jmobius.gameserver.geoengine.GeoEngine;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.actor.Summon;
import org.l2jmobius.gameserver.model.item.instance.Item;
import org.l2jmobius.gameserver.model.skill.Skill;
@@ -327,9 +328,17 @@ public class SummonAI extends PlayableAI implements Runnable
}
final Summon summon = getActor();
if ((summon.getOwner() != null) && (summon.getOwner() != attacker) && !summon.isMoving() && summon.canAttack(attacker, false))
final Player owner = summon.getOwner();
if (owner != null)
{
summon.doAttack(attacker);
if (summon.calculateDistance3D(owner) > 3000)
{
summon.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, owner);
}
else if ((owner != attacker) && !summon.isMoving() && summon.canAttack(attacker, false))
{
summon.doAttack(attacker);
}
}
}

View File

@@ -420,7 +420,6 @@ public class ClanTable
private void restoreClanWars()
{
final long currentTime = System.currentTimeMillis();
try (Connection con = DatabaseFactory.getConnection();
Statement statement = con.createStatement();
ResultSet rset = statement.executeQuery("SELECT clan1, clan2, clan1Kill, clan2Kill, winnerClan, startTime, endTime, state FROM clan_wars"))
@@ -431,14 +430,8 @@ public class ClanTable
final Clan attacked = getClan(rset.getInt("clan2"));
if ((attacker != null) && (attacked != null))
{
final long endTime = rset.getLong("endTime");
if (endTime < currentTime)
{
continue;
}
final ClanWarState state = ClanWarState.values()[rset.getInt("state")];
final ClanWar clanWar = new ClanWar(attacker, attacked, rset.getInt("clan1Kill"), rset.getInt("clan2Kill"), rset.getInt("winnerClan"), rset.getLong("startTime"), endTime, state);
final ClanWar clanWar = new ClanWar(attacker, attacked, rset.getInt("clan1Kill"), rset.getInt("clan2Kill"), rset.getInt("winnerClan"), rset.getLong("startTime"), rset.getLong("endTime"), state);
attacker.addWar(attacked.getId(), clanWar);
attacked.addWar(attacker.getId(), clanWar);
}

View File

@@ -88,6 +88,11 @@ public class ActionData implements IXmlReader
return _actionSkillsData.getOrDefault(skillId, -1);
}
public int[] getActionIdList()
{
return _actionData.keySet().stream().mapToInt(Number::intValue).toArray();
}
/**
* Gets the single instance of ActionData.
* @return single instance of ActionData

View File

@@ -307,7 +307,7 @@ public class InitialShortcutData implements IXmlReader
// Register shortcut
final Shortcut newShortcut = new Shortcut(shortcut.getSlot(), shortcut.getPage(), shortcut.getType(), shortcutId, shortcut.getLevel(), shortcut.getSubLevel(), shortcut.getCharacterType());
player.sendPacket(new ShortCutRegister(newShortcut));
player.sendPacket(new ShortCutRegister(newShortcut, player));
player.registerShortCut(newShortcut);
}
@@ -350,7 +350,7 @@ public class InitialShortcutData implements IXmlReader
}
// Register shortcut
final Shortcut newShortcut = new Shortcut(shortcut.getSlot(), shortcut.getPage(), shortcut.getType(), shortcutId, shortcut.getLevel(), shortcut.getSubLevel(), shortcut.getCharacterType());
player.sendPacket(new ShortCutRegister(newShortcut));
player.sendPacket(new ShortCutRegister(newShortcut, player));
player.registerShortCut(newShortcut);
}
}

View File

@@ -546,9 +546,10 @@ public class SkillData implements IXmlReader
variables.put("index", (i - fromLevel) + 1d);
variables.put("subIndex", (j - fromSubLevel) + 1d);
final Object base = values.getOrDefault(i, Collections.emptyMap()).get(-1);
if ((base != null) && !(base instanceof StatSet))
final String baseText = String.valueOf(base);
if ((base != null) && !(base instanceof StatSet) && (!baseText.equalsIgnoreCase("true") && !baseText.equalsIgnoreCase("false")))
{
variables.put("base", Double.parseDouble(String.valueOf(base)));
variables.put("base", Double.parseDouble(baseText));
}
parsedValue = parseValue(n, false, false, variables);
if (parsedValue != null)

View File

@@ -33,7 +33,6 @@ import org.l2jmobius.gameserver.model.actor.transform.TransformTemplate;
import org.l2jmobius.gameserver.model.holders.AdditionalItemHolder;
import org.l2jmobius.gameserver.model.holders.AdditionalSkillHolder;
import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList;
/**
* Transformation data.
@@ -142,7 +141,7 @@ public class TransformData implements IXmlReader
}
set.set("actions", z.getTextContent());
final int[] actions = set.getIntArray("actions", " ");
templateData.setBasicActionList(new ExBasicActionList(actions));
templateData.setBasicActionList(actions);
break;
}
case "additionalSkills":

View File

@@ -30,14 +30,14 @@ public enum NpcInfoType implements IUpdateTypeComponent
NAME(0x03, 2),
POSITION(0x04, (3 * 4)),
HEADING(0x05, 4),
UNKNOWN2(0x06, 4),
VEHICLE_ID(0x06, 4),
ATK_CAST_SPEED(0x07, (2 * 4)),
// 1
SPEED_MULTIPLIER(0x08, (2 * 4)),
EQUIPPED(0x09, (3 * 4)),
ALIVE(0x0A, 1),
RUNNING(0x0B, 1),
STOP_MODE(0x0A, 1),
MOVE_MODE(0x0B, 1),
SWIM_OR_FLY(0x0E, 1),
TEAM(0x0F, 1),
@@ -45,7 +45,7 @@ public enum NpcInfoType implements IUpdateTypeComponent
ENCHANT(0x10, 4),
FLYING(0x11, 4),
CLONE(0x12, 4),
COLOR_EFFECT(0x13, 4),
PET_EVOLUTION_ID(0x13, 4),
DISPLAY_EFFECT(0x16, 4),
TRANSFORMATION(0x17, 4),
@@ -55,7 +55,7 @@ public enum NpcInfoType implements IUpdateTypeComponent
MAX_HP(0x1A, 4),
MAX_MP(0x1B, 4),
SUMMONED(0x1C, 1),
UNKNOWN12(0x1D, (2 * 4)),
FOLLOW_INFO(0x1D, (2 * 4)),
TITLE(0x1E, 2),
NAME_NPCSTRINGID(0x1F, 4),

View File

@@ -25,4 +25,9 @@ import org.l2jmobius.gameserver.model.actor.Player;
public interface IPlayerActionHandler
{
void useAction(Player player, ActionDataHolder data, boolean ctrlPressed, boolean shiftPressed);
default boolean isPetAction()
{
return false;
}
}

View File

@@ -364,7 +364,11 @@ public class WalkingManager implements IXmlReader
final WalkInfo walk = _activeRoutes.remove(npc.getObjectId());
if (walk != null)
{
walk.getWalkCheckTask().cancel(true);
final ScheduledFuture<?> task = walk.getWalkCheckTask();
if (task != null)
{
task.cancel(true);
}
}
}

View File

@@ -215,7 +215,7 @@ public class ShortCuts implements IRestorable
{
final Shortcut newsc = new Shortcut(sc.getSlot(), sc.getPage(), sc.getType(), sc.getId(), skillLevel, skillSubLevel, 1);
newsc.setAutoUse(sc.isAutoUse());
_owner.sendPacket(new ShortCutRegister(newsc));
_owner.sendPacket(new ShortCutRegister(newsc, _owner));
_owner.registerShortCut(newsc);
}
}

View File

@@ -1288,7 +1288,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
player.updatePvPStatus(target);
}
if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer()))
if (isFakePlayer() && !Config.FAKE_PLAYER_AUTO_ATTACKABLE && (target.isPlayable() || target.isFakePlayer()))
{
final Npc npc = ((Npc) this);
if (!npc.isScriptValue(1))
@@ -2816,7 +2816,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
}
// If this creature was previously moving, but now due to stat change can no longer move, broadcast StopMove packet.
if (isMoving() && (_stat.getMoveSpeed() <= 0))
if (isMoving() && (getMoveSpeed() <= 0))
{
stopMove(null);
}
@@ -2829,177 +2829,139 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
summon.updateAndBroadcastStatus(1);
}
}
else
else if (isPlayer())
{
final boolean broadcastFull = true;
final StatusUpdate su = new StatusUpdate(this);
UserInfo info = null;
if (isPlayer())
final UserInfo info = new UserInfo(getActingPlayer(), false);
info.addComponentType(UserInfoType.SLOTS, UserInfoType.ENCHANTLEVEL);
boolean updateWeight = false;
for (Stat stat : currentChanges)
{
info = new UserInfo(getActingPlayer(), false);
info.addComponentType(UserInfoType.SLOTS, UserInfoType.ENCHANTLEVEL);
}
if (info != null)
{
for (Stat stat : currentChanges)
switch (stat)
{
switch (stat)
case MOVE_SPEED:
case RUN_SPEED:
case WALK_SPEED:
case SWIM_RUN_SPEED:
case SWIM_WALK_SPEED:
case FLY_RUN_SPEED:
case FLY_WALK_SPEED:
{
case MOVE_SPEED:
case RUN_SPEED:
case WALK_SPEED:
case SWIM_RUN_SPEED:
case SWIM_WALK_SPEED:
case FLY_RUN_SPEED:
case FLY_WALK_SPEED:
{
info.addComponentType(UserInfoType.MULTIPLIER);
break;
}
case PHYSICAL_ATTACK_SPEED:
{
info.addComponentType(UserInfoType.MULTIPLIER, UserInfoType.STATS);
break;
}
case PHYSICAL_ATTACK:
case PHYSICAL_DEFENCE:
case EVASION_RATE:
case ACCURACY_COMBAT:
case CRITICAL_RATE:
case MAGIC_CRITICAL_RATE:
case MAGIC_EVASION_RATE:
case ACCURACY_MAGIC:
case MAGIC_ATTACK:
case MAGIC_ATTACK_SPEED:
case MAGICAL_DEFENCE:
{
info.addComponentType(UserInfoType.STATS);
break;
}
case MAX_CP:
{
if (isPlayer())
{
info.addComponentType(UserInfoType.MAX_HPCPMP);
}
else
{
su.addUpdate(StatusUpdateType.MAX_CP, _stat.getMaxCp());
}
break;
}
case MAX_HP:
{
if (isPlayer())
{
info.addComponentType(UserInfoType.MAX_HPCPMP);
}
else
{
su.addUpdate(StatusUpdateType.MAX_HP, _stat.getMaxHp());
}
break;
}
case MAX_MP:
{
if (isPlayer())
{
info.addComponentType(UserInfoType.MAX_HPCPMP);
}
else
{
su.addUpdate(StatusUpdateType.MAX_CP, _stat.getMaxMp());
}
break;
}
case STAT_STR:
case STAT_CON:
case STAT_DEX:
case STAT_INT:
case STAT_WIT:
case STAT_MEN:
{
info.addComponentType(UserInfoType.BASE_STATS);
break;
}
case FIRE_RES:
case WATER_RES:
case WIND_RES:
case EARTH_RES:
case HOLY_RES:
case DARK_RES:
{
info.addComponentType(UserInfoType.ELEMENTALS);
break;
}
case FIRE_POWER:
case WATER_POWER:
case WIND_POWER:
case EARTH_POWER:
case HOLY_POWER:
case DARK_POWER:
{
info.addComponentType(UserInfoType.ATK_ELEMENTAL);
break;
}
info.addComponentType(UserInfoType.MULTIPLIER);
break;
}
case PHYSICAL_ATTACK_SPEED:
{
info.addComponentType(UserInfoType.MULTIPLIER, UserInfoType.STATS);
break;
}
case PHYSICAL_ATTACK:
case PHYSICAL_DEFENCE:
case EVASION_RATE:
case ACCURACY_COMBAT:
case CRITICAL_RATE:
case MAGIC_CRITICAL_RATE:
case MAGIC_EVASION_RATE:
case ACCURACY_MAGIC:
case MAGIC_ATTACK:
case MAGIC_ATTACK_SPEED:
case MAGICAL_DEFENCE:
{
info.addComponentType(UserInfoType.STATS);
break;
}
case MAX_CP:
{
info.addComponentType(UserInfoType.MAX_HPCPMP);
break;
}
case MAX_HP:
{
info.addComponentType(UserInfoType.MAX_HPCPMP);
break;
}
case MAX_MP:
{
info.addComponentType(UserInfoType.MAX_HPCPMP);
break;
}
case STAT_STR:
case STAT_CON:
case STAT_DEX:
case STAT_INT:
case STAT_WIT:
case STAT_MEN:
{
info.addComponentType(UserInfoType.BASE_STATS);
updateWeight = true;
break;
}
case FIRE_RES:
case WATER_RES:
case WIND_RES:
case EARTH_RES:
case HOLY_RES:
case DARK_RES:
{
info.addComponentType(UserInfoType.ELEMENTALS);
break;
}
case FIRE_POWER:
case WATER_POWER:
case WIND_POWER:
case EARTH_POWER:
case HOLY_POWER:
case DARK_POWER:
{
info.addComponentType(UserInfoType.ATK_ELEMENTAL);
break;
}
case WEIGHT_LIMIT:
case WEIGHT_PENALTY:
{
updateWeight = true;
break;
}
}
// currentChanges.clear();
}
if (isPlayer())
final Player player = getActingPlayer();
if (updateWeight)
{
final Player player = getActingPlayer();
player.refreshOverloaded(true);
sendPacket(info);
}
sendPacket(info);
player.broadcastCharInfo();
if (hasServitors() && hasAbnormalType(AbnormalType.ABILITY_CHANGE))
{
getServitors().values().forEach(Summon::broadcastStatusUpdate);
}
}
else if (isNpc())
{
World.getInstance().forEachVisibleObject(this, Player.class, player ->
{
if (!isVisibleFor(player))
{
return;
}
if (broadcastFull)
if (isFakePlayer())
{
player.broadcastCharInfo();
player.sendPacket(new FakePlayerInfo((Npc) this));
}
else if (su.hasUpdates())
else if (getRunSpeed() == 0)
{
broadcastPacket(su);
player.sendPacket(new ServerObjectInfo((Npc) this, player));
}
if (hasServitors() && hasAbnormalType(AbnormalType.ABILITY_CHANGE))
else
{
getServitors().values().forEach(Summon::broadcastStatusUpdate);
player.sendPacket(new NpcInfo((Npc) this));
}
}
else if (isNpc())
{
if (broadcastFull)
{
World.getInstance().forEachVisibleObject(this, Player.class, player ->
{
if (!isVisibleFor(player))
{
return;
}
if (isFakePlayer())
{
player.sendPacket(new FakePlayerInfo((Npc) this));
}
else if (_stat.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((Npc) this, player));
}
else
{
player.sendPacket(new NpcInfo((Npc) this));
}
});
}
else if (su.hasUpdates())
{
broadcastPacket(su);
}
}
else if (su.hasUpdates())
{
broadcastPacket(su);
}
});
}
_broadcastModifiedStatTask = null;

View File

@@ -4573,7 +4573,7 @@ public class Player extends Playable
{
super.doAutoAttack(target);
setRecentFakeDeath(false);
if (target.isFakePlayer())
if (target.isFakePlayer() && !Config.FAKE_PLAYER_AUTO_ATTACKABLE)
{
updatePvPStatus();
}
@@ -8455,9 +8455,13 @@ public class Player extends Playable
if ((getWantsPeace() == 0) && (attackerPlayer.getWantsPeace() == 0) && !isAcademyMember())
{
final ClanWar war = attackerClan.getWarWith(getClanId());
if ((war != null) && ((war.getState() == ClanWarState.MUTUAL) || (((war.getState() == ClanWarState.BLOOD_DECLARATION) || (war.getState() == ClanWarState.DECLARATION)) && (war.getAttackerClanId() == attackerClan.getId()))))
if (war != null)
{
return true;
final ClanWarState warState = war.getState();
if ((warState == ClanWarState.MUTUAL) || (((warState == ClanWarState.BLOOD_DECLARATION) || (warState == ClanWarState.DECLARATION)) && (war.getAttackerClanId() == clan.getId())))
{
return true;
}
}
}
}

View File

@@ -68,9 +68,9 @@ import org.l2jmobius.gameserver.network.serverpackets.ExPartyPetWindowUpdate;
import org.l2jmobius.gameserver.network.serverpackets.ExPetInfo;
import org.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
import org.l2jmobius.gameserver.network.serverpackets.PetDelete;
import org.l2jmobius.gameserver.network.serverpackets.PetInfo;
import org.l2jmobius.gameserver.network.serverpackets.PetItemList;
import org.l2jmobius.gameserver.network.serverpackets.PetStatusUpdate;
import org.l2jmobius.gameserver.network.serverpackets.PetSummonInfo;
import org.l2jmobius.gameserver.network.serverpackets.RelationChanged;
import org.l2jmobius.gameserver.network.serverpackets.ServerPacket;
import org.l2jmobius.gameserver.network.serverpackets.SummonInfo;
@@ -211,7 +211,7 @@ public abstract class Summon extends Playable
{
if (player == _owner)
{
player.sendPacket(new PetInfo(this, 1));
player.sendPacket(new PetSummonInfo(this, 1));
return;
}
@@ -375,10 +375,7 @@ public abstract class Summon extends Playable
@Override
public void onDecay()
{
if (!isPet())
{
super.onDecay();
}
unSummon(_owner);
deleteMe(_owner);
}
@@ -412,14 +409,18 @@ public abstract class Summon extends Playable
}
}
// pet will be deleted along with all his items
// Pet will be deleted along with all his items.
if (getInventory() != null)
{
getInventory().destroyAllItems("pet deleted", _owner, this);
}
decayMe();
CharSummonTable.getInstance().removeServitor(_owner, getObjectId());
if (!isPet())
{
CharSummonTable.getInstance().removeServitor(_owner, getObjectId());
}
}
public void unSummon(Player owner)
@@ -854,7 +855,7 @@ public abstract class Summon extends Playable
if (isSpawned())
{
sendPacket(new PetInfo(this, value));
sendPacket(new PetSummonInfo(this, value));
sendPacket(new PetStatusUpdate(this));
broadcastNpcInfo(value);
@@ -875,7 +876,14 @@ public abstract class Summon extends Playable
return;
}
player.sendPacket(new ExPetInfo(this, player, value));
if (isPet())
{
player.sendPacket(new ExPetInfo(this, player, value));
}
else
{
player.sendPacket(new SummonInfo(this, player, value));
}
});
}
@@ -900,7 +908,7 @@ public abstract class Summon extends Playable
// Check if the Player is the owner of the Pet
if (player == _owner)
{
player.sendPacket(new PetInfo(this, isDead() ? 0 : 1));
player.sendPacket(new PetSummonInfo(this, isDead() ? 0 : 1));
if (isPet())
{
player.sendPacket(new PetItemList(getInventory().getItems()));
@@ -908,7 +916,14 @@ public abstract class Summon extends Playable
}
else
{
player.sendPacket(new ExPetInfo(this, player, 0));
if (isPet())
{
player.sendPacket(new ExPetInfo(this, player, 0));
}
else
{
player.sendPacket(new SummonInfo(this, player, 0));
}
}
}
@@ -954,7 +969,7 @@ public abstract class Summon extends Playable
{
setTarget(target);
getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
if (target.isFakePlayer())
if (target.isFakePlayer() && !Config.FAKE_PLAYER_AUTO_ATTACKABLE)
{
_owner.updatePvPStatus();
}

View File

@@ -596,6 +596,8 @@ public class Door extends Creature
{
if (isVisibleFor(player))
{
player.sendPacket(new StaticObjectInfo(this, player.isGM()));
player.sendPacket(new DoorStatusUpdate(this));
if (getEmitter() > 0)
{
if (_isInverted)
@@ -607,7 +609,6 @@ public class Door extends Creature
player.sendPacket(new OnEventTrigger(getEmitter(), _open));
}
}
player.sendPacket(new StaticObjectInfo(this, player.isGM()));
}
}

View File

@@ -67,7 +67,7 @@ public class Monster extends Attackable
{
if (isFakePlayer())
{
return isInCombat() || attacker.isMonster() || (getScriptValue() > 0);
return Config.FAKE_PLAYER_AUTO_ATTACKABLE || isInCombat() || attacker.isMonster() || (getScriptValue() > 0);
}
// Check if the Monster target is aggressive

View File

@@ -16,6 +16,7 @@
*/
package org.l2jmobius.gameserver.model.actor.stat;
import java.util.Collections;
import java.util.Deque;
import java.util.EnumMap;
import java.util.EnumSet;
@@ -61,8 +62,6 @@ public class CreatureStat
private final Map<Stat, Double> _statsAdd = new EnumMap<>(Stat.class);
private final Map<Stat, Double> _statsMul = new EnumMap<>(Stat.class);
private final Map<Stat, Double> _addValueCache = new EnumMap<>(Stat.class);
private final Map<Stat, Double> _mulValueCache = new EnumMap<>(Stat.class);
private final Map<Stat, Map<MoveType, Double>> _moveTypeStats = new ConcurrentHashMap<>();
private final Map<Integer, Double> _reuseStat = new ConcurrentHashMap<>();
private final Map<Integer, Double> _mpConsumeStat = new ConcurrentHashMap<>();
@@ -873,15 +872,13 @@ public class CreatureStat
// Initialize default values
for (Stat stat : Stat.values())
{
final Double resetAddValue = stat.getResetAddValue();
if (resetAddValue.doubleValue() != 0)
if (stat.getResetAddValue() != 0)
{
_statsAdd.put(stat, resetAddValue);
_statsAdd.put(stat, stat.getResetAddValue());
}
final Double resetMulValue = stat.getResetMulValue();
if (resetMulValue.doubleValue() != 0)
if (stat.getResetMulValue() != 0)
{
_statsMul.put(stat, resetMulValue);
_statsMul.put(stat, stat.getResetMulValue());
}
}
}
@@ -892,8 +889,12 @@ public class CreatureStat
*/
public void recalculateStats(boolean broadcast)
{
Set<Stat> changed = null;
// Copy old data before wiping it out.
final Map<Stat, Double> adds = !broadcast ? Collections.emptyMap() : new EnumMap<>(_statsAdd);
final Map<Stat, Double> muls = !broadcast ? Collections.emptyMap() : new EnumMap<>(_statsMul);
_lock.writeLock().lock();
try
{
// Wipe all the data.
@@ -902,7 +903,7 @@ public class CreatureStat
// Call pump to each effect.
for (BuffInfo info : _creature.getEffectList().getPassives())
{
if (info.isInUse() && info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _creature, _creature))
if (info.isInUse() && info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _creature, _creature.getTarget()))
{
for (AbstractEffect effect : info.getEffects())
{
@@ -975,45 +976,26 @@ public class CreatureStat
}
_attackSpeedMultiplier = Formulas.calcAtkSpdMultiplier(_creature);
_mAttackSpeedMultiplier = Formulas.calcMAtkSpdMultiplier(_creature);
if (broadcast)
{
// Calculate the difference between old and new stats.
changed = EnumSet.noneOf(Stat.class);
for (Stat stat : Stat.values())
{
// Check if add value changed for this stat.
final Double resetAddValue = stat.getResetAddValue();
final Double addValue = _statsAdd.getOrDefault(stat, resetAddValue);
if (addValue.doubleValue() != _addValueCache.getOrDefault(stat, resetAddValue).doubleValue())
{
_addValueCache.put(stat, addValue);
changed.add(stat);
}
else // Check if mul value changed for this stat.
{
final Double resetMulValue = stat.getResetMulValue();
final Double mulValue = _statsMul.getOrDefault(stat, resetMulValue);
if (mulValue.doubleValue() != _mulValueCache.getOrDefault(stat, resetMulValue).doubleValue())
{
_mulValueCache.put(stat, mulValue);
changed.add(stat);
}
}
}
}
}
finally
{
_lock.writeLock().unlock();
}
// Notify recalculation to child classes.
// Notify recalculation to child classes
onRecalculateStats(broadcast);
// Broadcast changes.
if ((changed != null) && !changed.isEmpty())
if (broadcast)
{
// Calculate the difference between old and new stats
final Set<Stat> changed = EnumSet.noneOf(Stat.class);
for (Stat stat : Stat.values())
{
if (_statsAdd.getOrDefault(stat, stat.getResetAddValue()).equals(adds.getOrDefault(stat, stat.getResetAddValue())) || _statsMul.getOrDefault(stat, stat.getResetMulValue()).equals(muls.getOrDefault(stat, stat.getResetMulValue())))
{
changed.add(stat);
}
}
_creature.broadcastModifiedStats(changed);
}
}

View File

@@ -122,7 +122,7 @@ public class Transform implements IIdentifiable
return _title;
}
private TransformTemplate getTemplate(Creature creature)
public TransformTemplate getTemplate(Creature creature)
{
if (creature.isPlayer())
{
@@ -318,7 +318,7 @@ public class Transform implements IIdentifiable
// Send basic action list.
if (template.hasBasicActionList())
{
player.sendPacket(template.getBasicActionList());
player.sendPacket(new ExBasicActionList(template.getBasicActionList()));
}
player.getEffectList().stopAllToggles();

View File

@@ -30,7 +30,6 @@ import org.l2jmobius.gameserver.model.holders.SkillHolder;
import org.l2jmobius.gameserver.model.item.type.WeaponType;
import org.l2jmobius.gameserver.model.itemcontainer.Inventory;
import org.l2jmobius.gameserver.model.stats.Stat;
import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList;
/**
* @author UnAfraid
@@ -45,8 +44,7 @@ public class TransformTemplate
private List<AdditionalItemHolder> _additionalItems;
private Map<Integer, Integer> _baseDefense;
private Map<Integer, Double> _baseStats;
private ExBasicActionList _list;
private int[] _actions;
private final Map<Integer, TransformLevelData> _data = new LinkedHashMap<>(100);
public TransformTemplate(StatSet set)
@@ -282,19 +280,19 @@ public class TransformTemplate
return _additionalItems != null ? _additionalItems : Collections.emptyList();
}
public void setBasicActionList(ExBasicActionList list)
public void setBasicActionList(int[] actions)
{
_list = list;
_actions = actions;
}
public ExBasicActionList getBasicActionList()
public int[] getBasicActionList()
{
return _list;
return _actions;
}
public boolean hasBasicActionList()
{
return _list != null;
return _actions != null;
}
public void addLevelData(TransformLevelData data)

View File

@@ -184,7 +184,7 @@ public class ClanWar
_winnerClanId = winnerClan.getId();
_endTime = System.currentTimeMillis();
ThreadPool.schedule(() -> ClanTable.getInstance().deleteClanWars(cancelor.getId(), winnerClan.getId()), (_endTime + TIME_TO_DELETION_AFTER_DEFEAT) - System.currentTimeMillis());
ThreadPool.schedule(() -> ClanTable.getInstance().deleteClanWars(cancelor.getId(), winnerClan.getId()), 5000 /* (_endTime + TIME_TO_DELETION_AFTER_DEFEAT) - System.currentTimeMillis() */);
}
public void clanWarTimeout()
@@ -203,7 +203,7 @@ public class ClanWar
_state = ClanWarState.TIE;
_endTime = System.currentTimeMillis();
ThreadPool.schedule(() -> ClanTable.getInstance().deleteClanWars(attackerClan.getId(), attackedClan.getId()), (_endTime + TIME_TO_DELETION_AFTER_CANCELLATION) - System.currentTimeMillis());
ThreadPool.schedule(() -> ClanTable.getInstance().deleteClanWars(attackerClan.getId(), attackedClan.getId()), 5000 /* (_endTime + TIME_TO_DELETION_AFTER_CANCELLATION) - System.currentTimeMillis() */);
}
}

View File

@@ -57,7 +57,10 @@ public enum CommissionItemType
NECKLACE(31),
BELT(32),
BRACELET(33),
AGATHION(62),
HAIR_ACCESSORY(34),
BROOCH_JEWEL(63),
ARTIFACT(64),
// Supplies
POTION(35),
SCROLL_ENCHANT_WEAPON(36),
@@ -65,6 +68,7 @@ public enum CommissionItemType
SCROLL_OTHER(38),
SOULSHOT(39),
SPIRITSHOT(40),
OTHER_SUPPLIES(41),
// Pet Goods
PET_EQUIPMENT(42),
PET_SUPPLIES(43),

View File

@@ -47,8 +47,8 @@ public enum CommissionTreeType
CommissionItemType.SPEAR,
CommissionItemType.OTHER_WEAPON),
ARMOR(1, CommissionItemType.HELMET, CommissionItemType.ARMOR_TOP, CommissionItemType.ARMOR_PANTS, CommissionItemType.FULL_BODY, CommissionItemType.GLOVES, CommissionItemType.FEET, CommissionItemType.SHIELD, CommissionItemType.SIGIL, CommissionItemType.UNDERWEAR, CommissionItemType.CLOAK),
ACCESSORY(2, CommissionItemType.RING, CommissionItemType.EARRING, CommissionItemType.NECKLACE, CommissionItemType.BELT, CommissionItemType.BRACELET, CommissionItemType.HAIR_ACCESSORY),
SUPPLIES(3, CommissionItemType.POTION, CommissionItemType.SCROLL_ENCHANT_WEAPON, CommissionItemType.SCROLL_ENCHANT_ARMOR, CommissionItemType.SCROLL_OTHER, CommissionItemType.SOULSHOT, CommissionItemType.SPIRITSHOT),
ACCESSORY(2, CommissionItemType.RING, CommissionItemType.EARRING, CommissionItemType.NECKLACE, CommissionItemType.BELT, CommissionItemType.BRACELET, CommissionItemType.AGATHION, CommissionItemType.HAIR_ACCESSORY, CommissionItemType.BROOCH_JEWEL, CommissionItemType.ARTIFACT),
SUPPLIES(3, CommissionItemType.POTION, CommissionItemType.SCROLL_ENCHANT_WEAPON, CommissionItemType.SCROLL_ENCHANT_ARMOR, CommissionItemType.SCROLL_OTHER, CommissionItemType.SOULSHOT, CommissionItemType.SPIRITSHOT, CommissionItemType.OTHER_SUPPLIES),
PET_GOODS(4, CommissionItemType.PET_EQUIPMENT, CommissionItemType.PET_SUPPLIES),
MISC(
5,

View File

@@ -62,5 +62,6 @@ public enum EffectType
SUMMON_NPC,
TELEPORT,
TELEPORT_TO_TARGET,
ABNORMAL_SHIELD
ABNORMAL_SHIELD,
RESTORE_SYMBOL_SEAL
}

View File

@@ -2242,6 +2242,17 @@ public abstract class AbstractScript extends ManagedScript implements IEventTime
summoner.addSummonedNpc(npc);
}
// Retain monster original position if ENABLE_RANDOM_MONSTER_SPAWNS is enabled.
if (Config.ENABLE_RANDOM_MONSTER_SPAWNS && !randomOffset && npc.isMonster())
{
spawn.setXYZ(x, y, zValue);
npc.setXYZ(x, y, zValue);
if (heading > -1)
{
npc.setHeading(heading);
}
}
// Fixes invisible NPCs spawned by script.
npc.broadcastInfo();

View File

@@ -39,6 +39,7 @@ import org.l2jmobius.commons.util.StringUtil;
import org.l2jmobius.gameserver.data.ItemTable;
import org.l2jmobius.gameserver.data.xml.AgathionData;
import org.l2jmobius.gameserver.data.xml.AppearanceItemData;
import org.l2jmobius.gameserver.data.xml.ArmorSetData;
import org.l2jmobius.gameserver.data.xml.EnchantItemOptionsData;
import org.l2jmobius.gameserver.data.xml.EnsoulData;
import org.l2jmobius.gameserver.data.xml.OptionData;
@@ -52,6 +53,7 @@ import org.l2jmobius.gameserver.instancemanager.CastleManager;
import org.l2jmobius.gameserver.instancemanager.IdManager;
import org.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import org.l2jmobius.gameserver.instancemanager.SiegeGuardManager;
import org.l2jmobius.gameserver.model.ArmorSet;
import org.l2jmobius.gameserver.model.DropProtection;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.VariationInstance;
@@ -74,12 +76,14 @@ import org.l2jmobius.gameserver.model.events.impl.item.OnItemEnchantAdd;
import org.l2jmobius.gameserver.model.events.impl.item.OnItemSoulCrystalAdd;
import org.l2jmobius.gameserver.model.events.impl.item.OnItemTalk;
import org.l2jmobius.gameserver.model.holders.AgathionSkillHolder;
import org.l2jmobius.gameserver.model.holders.ArmorsetSkillHolder;
import org.l2jmobius.gameserver.model.instancezone.Instance;
import org.l2jmobius.gameserver.model.item.Armor;
import org.l2jmobius.gameserver.model.item.EtcItem;
import org.l2jmobius.gameserver.model.item.ItemTemplate;
import org.l2jmobius.gameserver.model.item.Weapon;
import org.l2jmobius.gameserver.model.item.appearance.AppearanceStone;
import org.l2jmobius.gameserver.model.item.appearance.AppearanceType;
import org.l2jmobius.gameserver.model.item.enchant.attribute.AttributeHolder;
import org.l2jmobius.gameserver.model.item.type.EtcItemType;
import org.l2jmobius.gameserver.model.item.type.ItemType;
@@ -94,6 +98,7 @@ import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.DropItem;
import org.l2jmobius.gameserver.network.serverpackets.GetItem;
import org.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
import org.l2jmobius.gameserver.network.serverpackets.SkillCoolTime;
import org.l2jmobius.gameserver.network.serverpackets.SpawnItem;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.taskmanager.ItemAppearanceTaskManager;
@@ -1652,7 +1657,9 @@ public class Item extends WorldObject
setDropperObjectId(dropper != null ? dropper.getObjectId() : 0); // Set the dropper Id for the knownlist packets in sendInfo
// Add the Item dropped in the world as a visible object
World.getInstance().addVisibleObject(this, getWorldRegion());
final WorldRegion region = getWorldRegion();
region.addVisibleObject(this);
World.getInstance().addVisibleObject(this, region);
if (Config.SAVE_DROPPED_ITEM)
{
ItemsOnGroundManager.getInstance().save(this);
@@ -2578,6 +2585,11 @@ public class Item extends WorldObject
}
}
public int getAppearanceStoneId()
{
return getVariables().getInt(ItemVariables.VISUAL_APPEARANCE_STONE_ID, 0);
}
public long getVisualLifeTime()
{
return getVariables().getLong(ItemVariables.VISUAL_APPEARANCE_LIFE_TIME, 0);
@@ -2602,6 +2614,8 @@ public class Item extends WorldObject
public void onVisualLifeTimeEnd()
{
removeVisualSetSkills();
final ItemVariables vars = getVariables();
vars.remove(ItemVariables.VISUAL_ID);
vars.remove(ItemVariables.VISUAL_APPEARANCE_STONE_ID);
@@ -2627,6 +2641,124 @@ public class Item extends WorldObject
}
}
public void removeVisualSetSkills()
{
if (!isEquipped())
{
return;
}
final int appearanceStoneId = getAppearanceStoneId();
if (appearanceStoneId > 0)
{
final AppearanceStone stone = AppearanceItemData.getInstance().getStone(appearanceStoneId);
if ((stone != null) && (stone.getType() == AppearanceType.FIXED))
{
final Player player = getActingPlayer();
if (player != null)
{
boolean update = false;
for (ArmorSet armorSet : ArmorSetData.getInstance().getSets(stone.getVisualId()))
{
if ((armorSet.getPiecesCount(player, Item::getVisualId) - 1 /* not removed yet */) < armorSet.getMinimumPieces())
{
for (ArmorsetSkillHolder holder : armorSet.getSkills())
{
final Skill skill = holder.getSkill();
if (skill != null)
{
player.removeSkill(skill, false, skill.isPassive());
update = true;
}
}
}
}
if (update)
{
player.sendSkillList();
}
}
}
}
}
public void applyVisualSetSkills()
{
if (!isEquipped())
{
return;
}
final int appearanceStoneId = getAppearanceStoneId();
if (appearanceStoneId > 0)
{
final AppearanceStone stone = AppearanceItemData.getInstance().getStone(appearanceStoneId);
if ((stone != null) && (stone.getType() == AppearanceType.FIXED))
{
final Player player = getActingPlayer();
if (player != null)
{
boolean update = false;
boolean updateTimeStamp = false;
for (ArmorSet armorSet : ArmorSetData.getInstance().getSets(stone.getVisualId()))
{
if (armorSet.getPiecesCount(player, Item::getVisualId) >= armorSet.getMinimumPieces())
{
for (ArmorsetSkillHolder holder : armorSet.getSkills())
{
if (player.getSkillLevel(holder.getSkillId()) >= holder.getSkillLevel())
{
continue;
}
final Skill skill = holder.getSkill();
if ((skill == null) || (skill.isPassive() && !skill.checkConditions(SkillConditionScope.PASSIVE, player, player)))
{
continue;
}
player.addSkill(skill, false);
update = true;
if (skill.isActive())
{
if (!player.hasSkillReuse(skill.getReuseHashCode()))
{
final int equipDelay = getEquipReuseDelay();
if (equipDelay > 0)
{
player.addTimeStamp(skill, equipDelay);
player.disableSkill(skill, equipDelay);
}
}
// Active, non offensive, skills start with reuse on equip.
if (!skill.isBad() && !skill.isTransformation() && (Config.ARMOR_SET_EQUIP_ACTIVE_SKILL_REUSE > 0) && player.hasEnteredWorld())
{
player.addTimeStamp(skill, skill.getReuseDelay() > 0 ? skill.getReuseDelay() : Config.ARMOR_SET_EQUIP_ACTIVE_SKILL_REUSE);
}
updateTimeStamp = true;
}
}
}
}
if (updateTimeStamp)
{
player.sendPacket(new SkillCoolTime(player));
}
if (update)
{
player.sendSkillList();
}
}
}
}
}
/**
* Returns the item in String format
* @return String

View File

@@ -772,7 +772,8 @@ public abstract class Inventory extends ItemContainer
final int itemVisualId = item.getVisualId();
if (itemVisualId > 0)
{
final AppearanceStone stone = AppearanceItemData.getInstance().getStone(itemVisualId);
final int appearanceStoneId = item.getAppearanceStoneId();
final AppearanceStone stone = AppearanceItemData.getInstance().getStone(appearanceStoneId > 0 ? appearanceStoneId : itemVisualId);
if ((stone != null) && (stone.getType() == AppearanceType.FIXED) && verifyAndApply(player, item, Item::getVisualId))
{
update = true;
@@ -924,7 +925,8 @@ public abstract class Inventory extends ItemContainer
final int itemVisualId = item.getVisualId();
if (itemVisualId > 0)
{
final AppearanceStone stone = AppearanceItemData.getInstance().getStone(itemVisualId);
final int appearanceStoneId = item.getAppearanceStoneId();
final AppearanceStone stone = AppearanceItemData.getInstance().getStone(appearanceStoneId > 0 ? appearanceStoneId : itemVisualId);
if ((stone != null) && (stone.getType() == AppearanceType.FIXED) && verifyAndRemove(player, item, Item::getVisualId))
{
remove = true;

View File

@@ -652,7 +652,7 @@ public class SkillCaster implements Runnable
((Creature) obj).addAttackerToAttackByList(caster);
// Summoning a servitor should not renew your own PvP flag time.
if (obj.isFakePlayer() && (!obj.isServitor() || (obj.getObjectId() != player.getFirstServitor().getObjectId())))
if (obj.isFakePlayer() && !Config.FAKE_PLAYER_AUTO_ATTACKABLE && (!obj.isServitor() || (obj.getObjectId() != player.getFirstServitor().getObjectId())))
{
player.updatePvPStatus();
}
@@ -675,7 +675,7 @@ public class SkillCaster implements Runnable
{
// Consider fake player PvP status.
if (!obj.isFakePlayer() //
|| (obj.isFakePlayer() && (!((Npc) obj).isScriptValue(0) || (((Npc) obj).getReputation() < 0))))
|| (obj.isFakePlayer() && !Config.FAKE_PLAYER_AUTO_ATTACKABLE && (!((Npc) obj).isScriptValue(0) || (((Npc) obj).getReputation() < 0))))
{
player.updatePvPStatus();
}
@@ -710,7 +710,7 @@ public class SkillCaster implements Runnable
}
});
}
else if (caster.isFakePlayer()) // fake player attacks player
else if (caster.isFakePlayer() && !Config.FAKE_PLAYER_AUTO_ATTACKABLE) // fake player attacks player
{
if (target.isPlayable() || target.isFakePlayer())
{

View File

@@ -91,6 +91,7 @@ public enum Stat
REAR_DAMAGE_RATE("rearDamage"),
DRAGON_WEAPON_DEFENCE("dragonWeaponDefence"),
AUTO_ATTACK_DAMAGE_BONUS("autoAttackDamageBonus"),
IGNORE_REDUCE_DAMAGE("ignoreReduceDamage"),
// PVP BONUS
PVP_PHYSICAL_ATTACK_DAMAGE("pvpPhysDmg"),
@@ -131,7 +132,8 @@ public enum Stat
SHIELD_DEFENCE_RATE("rShld", new ShieldDefenceRateFinalizer()),
CRITICAL_RATE("rCrit", new PCriticalRateFinalizer(), MathUtil::add, MathUtil::add, 0, 1),
CRITICAL_RATE_SKILL("physicalSkillCriticalRate"),
MAX_MAGIC_CRITICAL_RATE("maxMagicCritRate"),
ADD_MAX_MAGIC_CRITICAL_RATE("addMaxMagicCritRate"),
ADD_MAX_PHYSICAL_CRITICAL_RATE("addMaxPhysicalCritRate"),
MAGIC_CRITICAL_RATE("mCritRate", new MCritRateFinalizer()),
BLOW_RATE("blowRate"),
BLOW_RATE_DEFENCE("blowRateDefence"),

View File

@@ -43,7 +43,18 @@ public class MCritRateFinalizer implements IStatFunction
}
final double witBonus = creature.getWIT() > 0 ? BaseStat.WIT.calcBonus(creature) : 1;
return validateValue(creature, Stat.defaultValue(creature, stat, baseValue * witBonus * 10), 0, creature.isPlayable() ? creature.getStat().getValue(Stat.MAX_MAGIC_CRITICAL_RATE, Config.MAX_MCRIT_RATE) : Double.MAX_VALUE);
final double maxMagicalCritRate;
if (creature.isPlayable())
{
maxMagicalCritRate = Config.MAX_MCRIT_RATE + creature.getStat().getValue(Stat.ADD_MAX_MAGIC_CRITICAL_RATE, 0);
}
else
{
maxMagicalCritRate = Double.MAX_VALUE;
}
return validateValue(creature, Stat.defaultValue(creature, stat, baseValue * witBonus * 10), 0, maxMagicalCritRate);
}
@Override

View File

@@ -95,6 +95,6 @@ public class MDefenseFinalizer implements IStatFunction
{
final double mul = Math.max(creature.getStat().getMul(stat), 0.5);
final double add = creature.getStat().getAdd(stat);
return (baseValue * mul) + add + creature.getStat().getMoveTypeValue(stat, creature.getMoveType());
return Math.max((baseValue * mul) + add + creature.getStat().getMoveTypeValue(stat, creature.getMoveType()), creature.getTemplate().getBaseValue(stat, 0) * 0.2);
}
}

View File

@@ -42,7 +42,18 @@ public class PCriticalRateFinalizer implements IStatFunction
baseValue += calcEnchantBodyPart(creature, ItemTemplate.SLOT_LEGS);
}
final double dexBonus = creature.getDEX() > 0 ? BaseStat.DEX.calcBonus(creature) : 1;
return validateValue(creature, Stat.defaultValue(creature, stat, baseValue * dexBonus * 10), 0, creature.isPlayable() ? Config.MAX_PCRIT_RATE : Double.MAX_VALUE);
final double maxPhysicalCritRate;
if (creature.isPlayable())
{
maxPhysicalCritRate = Config.MAX_PCRIT_RATE + creature.getStat().getValue(Stat.ADD_MAX_PHYSICAL_CRITICAL_RATE, 0);
}
else
{
maxPhysicalCritRate = Double.MAX_VALUE;
}
return validateValue(creature, Stat.defaultValue(creature, stat, baseValue * dexBonus * 10), 0, maxPhysicalCritRate);
}
@Override

View File

@@ -97,6 +97,6 @@ public class PDefenseFinalizer implements IStatFunction
{
final double mul = Math.max(creature.getStat().getMul(stat), 0.5);
final double add = creature.getStat().getAdd(stat);
return (baseValue * mul) + add + creature.getStat().getMoveTypeValue(stat, creature.getMoveType());
return Math.max((baseValue * mul) + add + creature.getStat().getMoveTypeValue(stat, creature.getMoveType()), creature.getTemplate().getBaseValue(stat, 0) * 0.2);
}
}

View File

@@ -117,6 +117,11 @@ public class RequestAcquireSkill implements ClientPacket
final int skillId = player.getReplacementSkill(_id);
final Skill existingSkill = player.getKnownSkill(skillId); // Mobius: Keep existing sublevel.
if ((_level > 65536000) && (existingSkill != null) && (existingSkill.getSubLevel() > 1000))
{
_level -= existingSkill.getSubLevel() * 65536;
}
final Skill skill = SkillData.getInstance().getSkill(skillId, _level, existingSkill == null ? 0 : existingSkill.getSubLevel());
if (skill == null)
{
@@ -652,7 +657,7 @@ public class RequestAcquireSkill implements ClientPacket
player.sendItemList();
player.updateShortCuts(_id, skill.getLevel(), skill.getSubLevel());
player.sendPacket(new ShortCutInit(player));
player.sendPacket(new ExBasicActionList(ExBasicActionList.DEFAULT_ACTION_LIST));
player.sendPacket(ExBasicActionList.STATIC_PACKET);
player.sendSkillList(skill.getId());
showSkillList(trainer, player);

View File

@@ -25,6 +25,7 @@ import org.l2jmobius.gameserver.handler.IPlayerActionHandler;
import org.l2jmobius.gameserver.handler.PlayerActionHandler;
import org.l2jmobius.gameserver.model.ActionDataHolder;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.actor.transform.TransformTemplate;
import org.l2jmobius.gameserver.model.effects.AbstractEffect;
import org.l2jmobius.gameserver.model.skill.AbnormalType;
import org.l2jmobius.gameserver.model.skill.BuffInfo;
@@ -32,7 +33,6 @@ import org.l2jmobius.gameserver.network.GameClient;
import org.l2jmobius.gameserver.network.PacketLogger;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList;
import org.l2jmobius.gameserver.network.serverpackets.RecipeShopManageList;
/**
@@ -86,8 +86,9 @@ public class RequestActionUse implements ClientPacket
// Don't allow to do some action if player is transformed
if (player.isTransformed())
{
final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST;
if (Arrays.binarySearch(allowedActions, _actionId) < 0)
final TransformTemplate transformTemplate = player.getTransformation().get().getTemplate(player);
final int[] allowedActions = transformTemplate.getBasicActionList();
if ((allowedActions == null) || (Arrays.binarySearch(allowedActions, _actionId) < 0))
{
player.sendPacket(ActionFailed.STATIC_PACKET);
PacketLogger.warning(player + " used action which he does not have! Id = " + _actionId + " transform: " + player.getTransformation().get().getId());

View File

@@ -87,7 +87,7 @@ public class RequestShortCutReg implements ClientPacket
else if (_page == 23)
{
final Item item = player.getInventory().getItemByObjectId(_id);
if ((item != null) && !item.isPotion())
if (((item != null) && !item.isPotion()) || (_type == ShortcutType.ACTION))
{
return;
}
@@ -148,7 +148,7 @@ public class RequestShortCutReg implements ClientPacket
final Shortcut sc = new Shortcut(_slot, _page, _type, _id, _level, _subLevel, _characterType);
sc.setAutoUse(_active);
player.registerShortCut(sc);
player.sendPacket(new ShortCutRegister(sc));
player.sendPacket(new ShortCutRegister(sc, player));
player.sendPacket(new ExActivateAutoShortcut(sc, _active));
// When id is not auto used, deactivate auto shortcuts.

View File

@@ -229,6 +229,8 @@ public class RequestShapeShiftingItem implements ClientPacket
}
case FIXED:
{
targetItem.removeVisualSetSkills();
if (appearanceStone.getVisualIds().isEmpty())
{
extracItemId = appearanceStone.getVisualId();
@@ -245,6 +247,8 @@ public class RequestShapeShiftingItem implements ClientPacket
targetItem.getVariables().set(ItemVariables.VISUAL_APPEARANCE_STONE_ID, appearanceStone.getId());
}
}
targetItem.applyVisualSetSkills();
break;
}
}

View File

@@ -16,6 +16,7 @@
*/
package org.l2jmobius.gameserver.network.serverpackets;
import org.l2jmobius.gameserver.data.xml.ActionData;
import org.l2jmobius.gameserver.network.ServerPackets;
/**
@@ -23,128 +24,7 @@ import org.l2jmobius.gameserver.network.ServerPackets;
*/
public class ExBasicActionList extends ServerPacket
{
//@formatter:off
public static final int[] ACTIONS_ON_TRANSFORM =
{
1, 3, 4, 5,
6, 7, 8, 9,
11, 15, 16, 17,
18, 19, 21, 22,
23, 32, 36, 39,
40, 41, 42, 43,
44, 45, 46, 47,
48, 50, 52, 53,
54, 55, 56, 57,
63, 64, 65, 70,
86, 1000, 1001, 1003,
1004, 1005, 1006, 1007,
1008, 1009, 1010, 1011,
1012, 1013, 1014, 1015,
1016, 1017, 1018, 1019,
1020, 1021, 1022, 1023,
1024, 1025, 1026, 1027,
1028, 1029, 1030, 1031,
1032, 1033, 1034, 1035,
1036, 1037, 1038, 1039,
1040, 1041, 1042, 1043,
1044, 1045, 1046, 1047,
1048, 1049, 1050, 1051,
1052, 1053, 1054, 1055,
1056, 1057, 1058, 1059,
1060, 1061, 1062, 1063,
1064, 1065, 1066, 1067,
1068, 1069, 1070, 1071,
1072, 1073, 1074, 1075,
1076, 1077, 1078, 1079,
1080, 1081, 1082, 1083,
1084, 1089, 1090, 1091,
1092, 1093, 1094, 1095,
1096, 1097, 1098, 1099,
1100, 1101, 1102, 1103,
1104, 1106, 1107, 1108,
1109, 1110, 1111, 1113,
1114, 1115, 1116, 1117,
1118, 1120, 1121, 1124,
1125, 1126, 1127, 1128,
1129, 1130, 1131, 1132,
1133, 1134, 1135, 1136,
1137, 1138, 1139, 1140,
1141, 1142, 1143, 1144,
1145, 1146, 1147, 1148,
1149, 1150, 1151, 1152,
1153, 1154, 1155
};
public static final int[] DEFAULT_ACTION_LIST =
{
0, 1, 2, 3,
4, 5, 6, 7,
8, 9, 10, 11,
12, 13, 14, 15,
16, 17, 18, 19,
20, 21, 22, 23,
24, 25, 26, 27,
28, 29, 30, 31,
32, 33, 34, 35,
36, 37, 38, 39,
40, 41, 42, 43,
44, 45, 46, 47,
48, 49, 50, 51,
52, 53, 54, 55,
56, 57, 58, 59,
60, 61, 62, 63,
64, 65, 66, 67,
68, 69, 70, 71,
72, 73, 74, 76,
77, 78, 79, 80,
81, 82, 83, 84,
85, 86, 87, 88,
89, 90, 92, 93,
94, 1000, 1001,
1002, 1003, 1004, 1005,
1006, 1007, 1008, 1009,
1010, 1011, 1012, 1013,
1014, 1015, 1016, 1017,
1018, 1019, 1020, 1021,
1022, 1023, 1024, 1025,
1026, 1027, 1028, 1029,
1030, 1031, 1032, 1033,
1034, 1035, 1036, 1037,
1038, 1039, 1040, 1041,
1042, 1043, 1044, 1045,
1046, 1047, 1048, 1049,
1050, 1051, 1052, 1053,
1054, 1055, 1056, 1057,
1058, 1059, 1060, 1061,
1062, 1063, 1064, 1065,
1066, 1067, 1068, 1069,
1070, 1071, 1072, 1073,
1074, 1075, 1076, 1077,
1078, 1079, 1080, 1081,
1082, 1083, 1084, 1086,
1087, 1088, 1089, 1090,
1091, 1092, 1093, 1094,
1095, 1096, 1097, 1098,
1099, 1100, 1101, 1102,
1103, 1104, 1106, 1107,
1108, 1109, 1110, 1111,
1112, 1113, 1114, 1115,
1116, 1117, 1118, 1119,
1120, 1121, 1122, 1123,
1124, 1125, 1126, 1127,
1128, 1129, 1130, 1131,
1132, 1133, 1134, 1135,
1136, 1137, 1138, 1139,
1140, 1141, 1142, 1143,
1144, 1145, 1146, 1147,
1148, 1149, 1150, 1151,
1152, 1153, 1154, 1155,
5000, 5001, 5002, 5003,
5004, 5005, 5006, 5007,
5008, 5009, 5010, 5011,
5012, 5013, 5014, 5015
};
//@formatter:on
public static final ExBasicActionList STATIC_PACKET = new ExBasicActionList(DEFAULT_ACTION_LIST);
public static final ExBasicActionList STATIC_PACKET = new ExBasicActionList(ActionData.getInstance().getActionIdList());
private final int[] _actionIds;

View File

@@ -67,7 +67,7 @@ public class ExPetInfo extends AbstractMaskPacket<NpcInfoType>
_masks[2] |= 0x10;
addComponentType(NpcInfoType.NAME);
}
addComponentType(NpcInfoType.ATTACKABLE, NpcInfoType.RELATIONS, NpcInfoType.TITLE, NpcInfoType.ID, NpcInfoType.POSITION, NpcInfoType.ALIVE, NpcInfoType.RUNNING, NpcInfoType.PVP_FLAG);
addComponentType(NpcInfoType.ATTACKABLE, NpcInfoType.RELATIONS, NpcInfoType.TITLE, NpcInfoType.ID, NpcInfoType.POSITION, NpcInfoType.STOP_MODE, NpcInfoType.MOVE_MODE, NpcInfoType.PVP_FLAG);
if (summon.getHeading() > 0)
{
addComponentType(NpcInfoType.HEADING);
@@ -141,7 +141,7 @@ public class ExPetInfo extends AbstractMaskPacket<NpcInfoType>
_allyId = summon.getOwner().getAppearance().getVisibleAllyCrestId();
addComponentType(NpcInfoType.CLAN);
}
addComponentType(NpcInfoType.COLOR_EFFECT);
addComponentType(NpcInfoType.PET_EVOLUTION_ID);
// TODO: Confirm me
if (summon.isInCombat())
{
@@ -207,7 +207,7 @@ public class ExPetInfo extends AbstractMaskPacket<NpcInfoType>
{
ServerPackets.EX_PET_INFO.writeId(this);
writeInt(_summon.getObjectId());
writeByte(_value); // // 0=teleported 1=default 2=summoned
writeByte(_value); // 0=teleported 1=default 2=summoned
writeShort(37); // mask_bits_37
writeBytes(_masks);
// Block 1
@@ -240,9 +240,9 @@ public class ExPetInfo extends AbstractMaskPacket<NpcInfoType>
{
writeInt(_summon.getHeading());
}
if (containsMask(NpcInfoType.UNKNOWN2))
if (containsMask(NpcInfoType.VEHICLE_ID))
{
writeInt(0); // Unknown
writeInt(0); // Vehicle object id.
}
if (containsMask(NpcInfoType.ATK_CAST_SPEED))
{
@@ -260,11 +260,11 @@ public class ExPetInfo extends AbstractMaskPacket<NpcInfoType>
writeInt(_summon.getArmor()); // Armor id?
writeInt(0);
}
if (containsMask(NpcInfoType.ALIVE))
if (containsMask(NpcInfoType.STOP_MODE))
{
writeByte(!_summon.isDead());
}
if (containsMask(NpcInfoType.RUNNING))
if (containsMask(NpcInfoType.MOVE_MODE))
{
writeByte(_summon.isRunning());
}
@@ -288,9 +288,8 @@ public class ExPetInfo extends AbstractMaskPacket<NpcInfoType>
{
writeInt(0); // Player ObjectId with Decoy
}
if (containsMask(NpcInfoType.COLOR_EFFECT))
if (containsMask(NpcInfoType.PET_EVOLUTION_ID))
{
// No visual effect
writeInt(0); // Unknown
}
if (containsMask(NpcInfoType.DISPLAY_EFFECT))
@@ -321,7 +320,7 @@ public class ExPetInfo extends AbstractMaskPacket<NpcInfoType>
{
writeByte(_summon.isShowSummonAnimation() ? 2 : 0); // 2 - do some animation on spawn
}
if (containsMask(NpcInfoType.UNKNOWN12))
if (containsMask(NpcInfoType.FOLLOW_INFO))
{
writeInt(0);
writeInt(0);

View File

@@ -167,7 +167,7 @@ public class FakePlayerInfo extends ServerPacket
writeByte(_npc.getTeam().getId());
writeInt(_clan != null ? _clan.getCrestLargeId() : 0);
writeByte(_fpcHolder.getNobleLevel());
writeByte(_fpcHolder.isHero());
writeByte(_fpcHolder.isHero() ? 2 : 0); // 152 - Value for enabled changed to 2
writeByte(_fpcHolder.isFishing());
writeInt(_fpcHolder.getBaitLocationX());
writeInt(_fpcHolder.getBaitLocationY());

View File

@@ -61,7 +61,7 @@ public class NpcInfo extends AbstractMaskPacket<NpcInfoType>
{
_npc = npc;
_abnormalVisualEffects = npc.getEffectList().getCurrentAbnormalVisualEffects();
addComponentType(NpcInfoType.ATTACKABLE, NpcInfoType.RELATIONS, NpcInfoType.ID, NpcInfoType.POSITION, NpcInfoType.ALIVE, NpcInfoType.RUNNING);
addComponentType(NpcInfoType.ATTACKABLE, NpcInfoType.RELATIONS, NpcInfoType.ID, NpcInfoType.POSITION, NpcInfoType.STOP_MODE, NpcInfoType.MOVE_MODE);
if (npc.getHeading() > 0)
{
addComponentType(NpcInfoType.HEADING);
@@ -163,7 +163,7 @@ public class NpcInfo extends AbstractMaskPacket<NpcInfoType>
addComponentType(NpcInfoType.CLAN);
}
}
addComponentType(NpcInfoType.COLOR_EFFECT);
addComponentType(NpcInfoType.PET_EVOLUTION_ID);
if (npc.getPvpFlag() > 0)
{
addComponentType(NpcInfoType.PVP_FLAG);
@@ -323,9 +323,9 @@ public class NpcInfo extends AbstractMaskPacket<NpcInfoType>
{
writeInt(_npc.getHeading());
}
if (containsMask(NpcInfoType.UNKNOWN2))
if (containsMask(NpcInfoType.VEHICLE_ID))
{
writeInt(0); // Unknown
writeInt(0); // Vehicle object id.
}
if (containsMask(NpcInfoType.ATK_CAST_SPEED))
{
@@ -343,11 +343,11 @@ public class NpcInfo extends AbstractMaskPacket<NpcInfoType>
writeInt(0); // Armor id?
writeInt(_npc.getLeftHandItem());
}
if (containsMask(NpcInfoType.ALIVE))
if (containsMask(NpcInfoType.STOP_MODE))
{
writeByte(!_npc.isDead());
}
if (containsMask(NpcInfoType.RUNNING))
if (containsMask(NpcInfoType.MOVE_MODE))
{
writeByte(_npc.isRunning());
}
@@ -371,9 +371,9 @@ public class NpcInfo extends AbstractMaskPacket<NpcInfoType>
{
writeInt(_npc.getCloneObjId()); // Player ObjectId with Decoy
}
if (containsMask(NpcInfoType.COLOR_EFFECT))
if (containsMask(NpcInfoType.PET_EVOLUTION_ID))
{
writeInt(_npc.getColorEffect()); // Color effect
writeInt(0); // Unknown
}
if (containsMask(NpcInfoType.DISPLAY_EFFECT))
{
@@ -403,7 +403,7 @@ public class NpcInfo extends AbstractMaskPacket<NpcInfoType>
{
writeByte(0); // 2 - do some animation on spawn
}
if (containsMask(NpcInfoType.UNKNOWN12))
if (containsMask(NpcInfoType.FOLLOW_INFO))
{
writeInt(0);
writeInt(0);

View File

@@ -1,182 +1,182 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.serverpackets;
import java.util.Set;
import org.l2jmobius.gameserver.model.actor.Summon;
import org.l2jmobius.gameserver.model.actor.instance.Pet;
import org.l2jmobius.gameserver.model.actor.instance.Servitor;
import org.l2jmobius.gameserver.model.skill.AbnormalVisualEffect;
import org.l2jmobius.gameserver.network.ServerPackets;
import org.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
public class PetInfo extends ServerPacket
{
private final Summon _summon;
private final int _value;
private final int _runSpd;
private final int _walkSpd;
private final int _swimRunSpd;
private final int _swimWalkSpd;
private final int _flRunSpd = 0;
private final int _flWalkSpd = 0;
private final int _flyRunSpd;
private final int _flyWalkSpd;
private final double _moveMultiplier;
private int _maxFed;
private int _curFed;
private int _statusMask = 0;
public PetInfo(Summon summon, int value)
{
_summon = summon;
_moveMultiplier = summon.getMovementSpeedMultiplier();
_runSpd = (int) Math.round(summon.getRunSpeed() / _moveMultiplier);
_walkSpd = (int) Math.round(summon.getWalkSpeed() / _moveMultiplier);
_swimRunSpd = (int) Math.round(summon.getSwimRunSpeed() / _moveMultiplier);
_swimWalkSpd = (int) Math.round(summon.getSwimWalkSpeed() / _moveMultiplier);
_flyRunSpd = summon.isFlying() ? _runSpd : 0;
_flyWalkSpd = summon.isFlying() ? _walkSpd : 0;
_value = value;
if (summon.isPet())
{
final Pet pet = (Pet) _summon;
_curFed = pet.getCurrentFed(); // how fed it is
_maxFed = pet.getMaxFed(); // max fed it can be
}
else if (summon.isServitor())
{
final Servitor sum = (Servitor) _summon;
_curFed = sum.getLifeTimeRemaining();
_maxFed = sum.getLifeTime();
}
if (summon.isBetrayed())
{
_statusMask |= 0x01; // Auto attackable status
}
_statusMask |= 0x02; // can be chatted with
if (summon.isRunning())
{
_statusMask |= 0x04;
}
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(summon))
{
_statusMask |= 0x08;
}
if (summon.isDead())
{
_statusMask |= 0x10;
}
if (summon.isMountable())
{
_statusMask |= 0x20;
}
}
@Override
public void write()
{
ServerPackets.PET_INFO.writeId(this);
writeByte(_summon.getSummonType());
writeInt(_summon.getObjectId());
writeInt(_summon.getTemplate().getDisplayId() + 1000000);
writeInt(_summon.getX());
writeInt(_summon.getY());
writeInt(_summon.getZ());
writeInt(_summon.getHeading());
writeInt(_summon.getStat().getMAtkSpd());
writeInt(_summon.getStat().getPAtkSpd());
writeShort(_runSpd);
writeShort(_walkSpd);
writeShort(_swimRunSpd);
writeShort(_swimWalkSpd);
writeShort(_flRunSpd);
writeShort(_flWalkSpd);
writeShort(_flyRunSpd);
writeShort(_flyWalkSpd);
writeDouble(_moveMultiplier);
writeDouble(_summon.getAttackSpeedMultiplier()); // attack speed multiplier
writeDouble(_summon.getTemplate().getFCollisionRadius());
writeDouble(_summon.getTemplate().getFCollisionHeight());
writeInt(_summon.getWeapon()); // right hand weapon
writeInt(_summon.getArmor()); // body armor
writeInt(0); // left hand weapon
writeByte(_summon.isShowSummonAnimation() ? 2 : _value); // 0=teleported 1=default 2=summoned
writeInt(-1); // High Five NPCString ID
if (_summon.isPet())
{
writeString(_summon.getName()); // Pet name.
}
else
{
writeString(_summon.getTemplate().isUsingServerSideName() ? _summon.getName() : ""); // Summon name.
}
writeInt(-1); // High Five NPCString ID
writeString(_summon.getTitle()); // owner name
writeByte(_summon.getPvpFlag()); // confirmed
writeInt(_summon.getReputation()); // confirmed
writeInt(_curFed); // how fed it is
writeInt(_maxFed); // max fed it can be
writeInt((int) _summon.getCurrentHp()); // current hp
writeInt(_summon.getMaxHp()); // max hp
writeInt((int) _summon.getCurrentMp()); // current mp
writeInt(_summon.getMaxMp()); // max mp
writeLong(_summon.getStat().getSp()); // sp
writeByte(_summon.getLevel()); // level
writeLong(_summon.getStat().getExp());
if (_summon.getExpForThisLevel() > _summon.getStat().getExp())
{
writeLong(_summon.getStat().getExp()); // 0% absolute value
}
else
{
writeLong(_summon.getExpForThisLevel()); // 0% absolute value
}
writeLong(_summon.getExpForNextLevel()); // 100% absoulte value
writeInt(_summon.isPet() ? _summon.getInventory().getTotalWeight() : 0); // weight
writeInt(_summon.getMaxLoad()); // max weight it can carry
writeInt(_summon.getPAtk()); // patk
writeInt(_summon.getPDef()); // pdef
writeInt(_summon.getAccuracy()); // accuracy
writeInt(_summon.getEvasionRate()); // evasion
writeInt(_summon.getCriticalHit()); // critical
writeInt(_summon.getMAtk()); // matk
writeInt(_summon.getMDef()); // mdef
writeInt(_summon.getMagicAccuracy()); // magic accuracy
writeInt(_summon.getMagicEvasionRate()); // magic evasion
writeInt(_summon.getMCriticalHit()); // mcritical
writeInt((int) _summon.getStat().getMoveSpeed()); // speed
writeInt(_summon.getPAtkSpd()); // atkspeed
writeInt(_summon.getMAtkSpd()); // casting speed
writeByte(0); // TODO: Check me, might be ride status
writeByte(_summon.getTeam().getId()); // Confirmed
writeByte(_summon.getSoulShotsPerHit()); // How many soulshots this servitor uses per hit - Confirmed
writeByte(_summon.getSpiritShotsPerHit()); // How many spiritshots this servitor uses per hit - - Confirmed
writeInt(0); // TODO: Find me
writeInt(0); // "Transformation ID - Confirmed" - Used to bug Fenrir after 64 level.
writeByte(_summon.getOwner().getSummonPoints()); // Used Summon Points
writeByte(_summon.getOwner().getMaxSummonPoints()); // Maximum Summon Points
final Set<AbnormalVisualEffect> aves = _summon.getEffectList().getCurrentAbnormalVisualEffects();
writeShort(aves.size()); // Confirmed
for (AbnormalVisualEffect ave : aves)
{
writeShort(ave.getClientId()); // Confirmed
}
writeByte(_statusMask);
}
}
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.network.serverpackets;
import java.util.Set;
import org.l2jmobius.gameserver.model.actor.Summon;
import org.l2jmobius.gameserver.model.actor.instance.Pet;
import org.l2jmobius.gameserver.model.actor.instance.Servitor;
import org.l2jmobius.gameserver.model.skill.AbnormalVisualEffect;
import org.l2jmobius.gameserver.network.ServerPackets;
import org.l2jmobius.gameserver.taskmanager.AttackStanceTaskManager;
public class PetSummonInfo extends ServerPacket
{
private final Summon _summon;
private final int _value;
private final int _runSpd;
private final int _walkSpd;
private final int _swimRunSpd;
private final int _swimWalkSpd;
private final int _flRunSpd = 0;
private final int _flWalkSpd = 0;
private final int _flyRunSpd;
private final int _flyWalkSpd;
private final double _moveMultiplier;
private int _maxFed;
private int _curFed;
private int _statusMask = 0;
public PetSummonInfo(Summon summon, int value)
{
_summon = summon;
_moveMultiplier = summon.getMovementSpeedMultiplier();
_runSpd = (int) Math.round(summon.getRunSpeed() / _moveMultiplier);
_walkSpd = (int) Math.round(summon.getWalkSpeed() / _moveMultiplier);
_swimRunSpd = (int) Math.round(summon.getSwimRunSpeed() / _moveMultiplier);
_swimWalkSpd = (int) Math.round(summon.getSwimWalkSpeed() / _moveMultiplier);
_flyRunSpd = summon.isFlying() ? _runSpd : 0;
_flyWalkSpd = summon.isFlying() ? _walkSpd : 0;
_value = value;
if (summon.isPet())
{
final Pet pet = (Pet) _summon;
_curFed = pet.getCurrentFed(); // how fed it is
_maxFed = pet.getMaxFed(); // max fed it can be
}
else if (summon.isServitor())
{
final Servitor sum = (Servitor) _summon;
_curFed = sum.getLifeTimeRemaining();
_maxFed = sum.getLifeTime();
}
if (summon.isBetrayed())
{
_statusMask |= 0x01; // Auto attackable status
}
_statusMask |= 0x02; // can be chatted with
if (summon.isRunning())
{
_statusMask |= 0x04;
}
if (AttackStanceTaskManager.getInstance().hasAttackStanceTask(summon))
{
_statusMask |= 0x08;
}
if (summon.isDead())
{
_statusMask |= 0x10;
}
if (summon.isMountable())
{
_statusMask |= 0x20;
}
}
@Override
public void write()
{
ServerPackets.PET_INFO.writeId(this);
writeByte(_summon.getSummonType());
writeInt(_summon.getObjectId());
writeInt(_summon.getTemplate().getDisplayId() + 1000000);
writeInt(_summon.getX());
writeInt(_summon.getY());
writeInt(_summon.getZ());
writeInt(_summon.getHeading());
writeInt(_summon.getStat().getMAtkSpd());
writeInt(_summon.getStat().getPAtkSpd());
writeShort(_runSpd);
writeShort(_walkSpd);
writeShort(_swimRunSpd);
writeShort(_swimWalkSpd);
writeShort(_flRunSpd);
writeShort(_flWalkSpd);
writeShort(_flyRunSpd);
writeShort(_flyWalkSpd);
writeDouble(_moveMultiplier);
writeDouble(_summon.getAttackSpeedMultiplier()); // attack speed multiplier
writeDouble(_summon.getTemplate().getFCollisionRadius());
writeDouble(_summon.getTemplate().getFCollisionHeight());
writeInt(_summon.getWeapon()); // right hand weapon
writeInt(_summon.getArmor()); // body armor
writeInt(0); // left hand weapon
writeByte(_summon.isShowSummonAnimation() ? 2 : _value); // 0=teleported 1=default 2=summoned
writeInt(-1); // High Five NPCString ID
if (_summon.isPet())
{
writeString(_summon.getName()); // Pet name.
}
else
{
writeString(_summon.getTemplate().isUsingServerSideName() ? _summon.getName() : ""); // Summon name.
}
writeInt(-1); // High Five NPCString ID
writeString(_summon.getTitle()); // owner name
writeByte(_summon.getPvpFlag()); // confirmed
writeInt(_summon.getReputation()); // confirmed
writeInt(_curFed); // how fed it is
writeInt(_maxFed); // max fed it can be
writeInt((int) _summon.getCurrentHp()); // current hp
writeInt(_summon.getMaxHp()); // max hp
writeInt((int) _summon.getCurrentMp()); // current mp
writeInt(_summon.getMaxMp()); // max mp
writeLong(_summon.getStat().getSp()); // sp
writeByte(_summon.getLevel()); // level
writeLong(_summon.getStat().getExp());
if (_summon.getExpForThisLevel() > _summon.getStat().getExp())
{
writeLong(_summon.getStat().getExp()); // 0% absolute value
}
else
{
writeLong(_summon.getExpForThisLevel()); // 0% absolute value
}
writeLong(_summon.getExpForNextLevel()); // 100% absoulte value
writeInt(_summon.isPet() ? _summon.getInventory().getTotalWeight() : 0); // weight
writeInt(_summon.getMaxLoad()); // max weight it can carry
writeInt(_summon.getPAtk()); // patk
writeInt(_summon.getPDef()); // pdef
writeInt(_summon.getAccuracy()); // accuracy
writeInt(_summon.getEvasionRate()); // evasion
writeInt(_summon.getCriticalHit()); // critical
writeInt(_summon.getMAtk()); // matk
writeInt(_summon.getMDef()); // mdef
writeInt(_summon.getMagicAccuracy()); // magic accuracy
writeInt(_summon.getMagicEvasionRate()); // magic evasion
writeInt(_summon.getMCriticalHit()); // mcritical
writeInt((int) _summon.getStat().getMoveSpeed()); // speed
writeInt(_summon.getPAtkSpd()); // atkspeed
writeInt(_summon.getMAtkSpd()); // casting speed
writeByte(0); // TODO: Check me, might be ride status
writeByte(_summon.getTeam().getId()); // Confirmed
writeByte(_summon.getSoulShotsPerHit()); // How many soulshots this servitor uses per hit - Confirmed
writeByte(_summon.getSpiritShotsPerHit()); // How many spiritshots this servitor uses per hit - - Confirmed
writeInt(0); // TODO: Find me
writeInt(0); // "Transformation ID - Confirmed" - Used to bug Fenrir after 64 level.
writeByte(_summon.getOwner().getSummonPoints()); // Used Summon Points
writeByte(_summon.getOwner().getMaxSummonPoints()); // Maximum Summon Points
final Set<AbnormalVisualEffect> aves = _summon.getEffectList().getCurrentAbnormalVisualEffects();
writeShort(aves.size()); // Confirmed
for (AbnormalVisualEffect ave : aves)
{
writeShort(ave.getClientId()); // Confirmed
}
writeByte(_statusMask);
}
}

View File

@@ -19,20 +19,21 @@ package org.l2jmobius.gameserver.network.serverpackets;
import java.util.Collection;
import org.l2jmobius.gameserver.model.Shortcut;
import org.l2jmobius.gameserver.model.VariationInstance;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.item.instance.Item;
import org.l2jmobius.gameserver.network.ServerPackets;
public class ShortCutInit extends ServerPacket
{
private Collection<Shortcut> _shortCuts;
private final Player _player;
private final Collection<Shortcut> _shortCuts;
public ShortCutInit(Player player)
{
if (player == null)
{
return;
}
_player = player;
_shortCuts = player.getAllShortCuts();
player.restoreAutoShortcutVisual();
}
@Override
@@ -54,8 +55,21 @@ public class ShortCutInit extends ServerPacket
writeInt(sc.getSharedReuseGroup());
writeInt(0);
writeInt(0);
writeLong(0); // Augment id
writeInt(0); // Visual id
final Item item = _player.getInventory().getItemByObjectId(sc.getId());
if (item != null)
{
final VariationInstance augment = item.getAugmentation();
writeInt(augment != null ? augment.getOption1Id() : 0); // item augment id
writeInt(augment != null ? augment.getOption2Id() : 0); // item augment id
writeInt(item.getVisualId()); // visual id
}
else
{
writeInt(0);
writeInt(0);
writeInt(0);
}
break;
}
case SKILL:

View File

@@ -17,18 +17,24 @@
package org.l2jmobius.gameserver.network.serverpackets;
import org.l2jmobius.gameserver.model.Shortcut;
import org.l2jmobius.gameserver.model.VariationInstance;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.item.instance.Item;
import org.l2jmobius.gameserver.network.ServerPackets;
public class ShortCutRegister extends ServerPacket
{
private final Player _player;
private final Shortcut _shortcut;
/**
* Register new skill shortcut
* @param shortcut
* @param player
*/
public ShortCutRegister(Shortcut shortcut)
public ShortCutRegister(Shortcut shortcut, Player player)
{
_player = player;
_shortcut = shortcut;
}
@@ -43,13 +49,16 @@ public class ShortCutRegister extends ServerPacket
{
case ITEM:
{
final Item item = _player.getInventory().getItemByObjectId(_shortcut.getId());
final VariationInstance augment = item.getAugmentation();
writeInt(_shortcut.getId());
writeInt(_shortcut.getCharacterType());
writeInt(_shortcut.getSharedReuseGroup());
writeInt(0); // unknown
writeInt(0); // unknown
writeInt(0); // item augment id
writeInt(0); // TODO: Find me, item visual id ?
writeInt(augment != null ? augment.getOption1Id() : 0); // item augment id
writeInt(augment != null ? augment.getOption2Id() : 0); // item augment id
writeInt(item.getVisualId()); // visual id
break;
}
case SKILL:
@@ -60,8 +69,8 @@ public class ShortCutRegister extends ServerPacket
writeInt(_shortcut.getSharedReuseGroup());
writeByte(0); // C5
writeInt(_shortcut.getCharacterType());
writeInt(0); // TODO: Find me
writeInt(0); // TODO: Find me
writeInt(0); // if 1 - cant use
writeInt(0); // reuse delay ?
break;
}
case ACTION:

View File

@@ -16,6 +16,9 @@
*/
package org.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List;
import org.l2jmobius.gameserver.data.sql.ClanTable;
import org.l2jmobius.gameserver.enums.SiegeClanType;
import org.l2jmobius.gameserver.model.SiegeClan;
@@ -44,7 +47,7 @@ import org.l2jmobius.gameserver.network.ServerPackets;
* S = AllyName<br>
* S = AllyLeaderName<br>
* d = AllyCrestID<br>
* @author KenM
* @author Atronic
*/
public class SiegeDefenderList extends ServerPacket
{
@@ -60,64 +63,76 @@ public class SiegeDefenderList extends ServerPacket
{
ServerPackets.CASTLE_SIEGE_DEFENDER_LIST.writeId(this);
writeInt(_castle.getResidenceId());
writeInt(0); // Unknown
writeInt(1); // Unknown
writeInt(0); // Unknown
final int size = _castle.getSiege().getDefenderWaitingClans().size() + _castle.getSiege().getDefenderClans().size() + (_castle.getOwner() != null ? 1 : 0);
writeInt(size);
writeInt(size);
// Add owners
final Clan ownerClan = _castle.getOwner();
if (ownerClan != null)
writeInt(0); // Unknown.
final Clan owner = _castle.getOwner();
writeInt((owner != null) && _castle.isTimeRegistrationOver()); // Valid registration.
writeInt(0); // Unknown.
// Add owners.
final List<Clan> defenders = new ArrayList<>();
if (owner != null)
{
writeInt(ownerClan.getId());
writeString(ownerClan.getName());
writeString(ownerClan.getLeaderName());
writeInt(ownerClan.getCrestId());
writeInt(0); // signed time (seconds) (not storated by L2J)
writeInt(SiegeClanType.OWNER.ordinal());
writeInt(ownerClan.getAllyId());
writeString(ownerClan.getAllyName());
writeString(""); // AllyLeaderName
writeInt(ownerClan.getAllyCrestId());
defenders.add(owner);
}
// List of confirmed defenders
// List of confirmed defenders.
for (SiegeClan siegeClan : _castle.getSiege().getDefenderClans())
{
final Clan defendingClan = ClanTable.getInstance().getClan(siegeClan.getClanId());
if ((defendingClan == null) || (defendingClan == _castle.getOwner()))
final Clan clan = ClanTable.getInstance().getClan(siegeClan.getClanId());
if ((clan != null) && (clan != owner))
{
continue;
defenders.add(clan);
}
writeInt(defendingClan.getId());
writeString(defendingClan.getName());
writeString(defendingClan.getLeaderName());
writeInt(defendingClan.getCrestId());
writeInt(0); // signed time (seconds) (not storated by L2J)
writeInt(SiegeClanType.DEFENDER.ordinal());
writeInt(defendingClan.getAllyId());
writeString(defendingClan.getAllyName());
writeString(""); // AllyLeaderName
writeInt(defendingClan.getAllyCrestId());
}
// List of not confirmed defenders
// List of not confirmed defenders.
for (SiegeClan siegeClan : _castle.getSiege().getDefenderWaitingClans())
{
final Clan defendingClan = ClanTable.getInstance().getClan(siegeClan.getClanId());
if (defendingClan == null)
final Clan clan = ClanTable.getInstance().getClan(siegeClan.getClanId());
if (clan != null)
{
continue;
defenders.add(clan);
}
}
final int size = defenders.size();
writeInt(size);
writeInt(size);
for (Clan clan : defenders)
{
writeInt(clan.getId());
writeString(clan.getName());
writeString(clan.getLeaderName());
writeInt(clan.getCrestId());
writeInt(0); // Signed time in seconds.
if (clan == owner)
{
writeInt(SiegeClanType.OWNER.ordinal() + 1);
}
else if (_castle.getSiege().getDefenderClans().stream().anyMatch(defender -> defender.getClanId() == clan.getId()))
{
writeInt(SiegeClanType.DEFENDER.ordinal() + 1);
}
else
{
writeInt(SiegeClanType.DEFENDER_PENDING.ordinal() + 1);
}
writeInt(clan.getAllyId());
if (clan.getAllyId() != 0)
{
final AllianceInfo info = new AllianceInfo(clan.getAllyId());
writeString(info.getName());
writeString(info.getLeaderP()); // Ally leader name.
writeInt(clan.getAllyCrestId());
}
else
{
writeString("");
writeString(""); // Ally leader name.
writeInt(0);
}
writeInt(defendingClan.getId());
writeString(defendingClan.getName());
writeString(defendingClan.getLeaderName());
writeInt(defendingClan.getCrestId());
writeInt(0); // signed time (seconds) (not storated by L2J)
writeInt(SiegeClanType.DEFENDER_PENDING.ordinal());
writeInt(defendingClan.getAllyId());
writeString(defendingClan.getAllyName());
writeString(""); // AllyLeaderName
writeInt(defendingClan.getAllyCrestId());
}
}
}

View File

@@ -67,7 +67,7 @@ public class SummonInfo extends AbstractMaskPacket<NpcInfoType>
_masks[2] |= 0x10;
addComponentType(NpcInfoType.NAME);
}
addComponentType(NpcInfoType.ATTACKABLE, NpcInfoType.RELATIONS, NpcInfoType.TITLE, NpcInfoType.ID, NpcInfoType.POSITION, NpcInfoType.ALIVE, NpcInfoType.RUNNING, NpcInfoType.PVP_FLAG);
addComponentType(NpcInfoType.ATTACKABLE, NpcInfoType.RELATIONS, NpcInfoType.TITLE, NpcInfoType.ID, NpcInfoType.POSITION, NpcInfoType.STOP_MODE, NpcInfoType.MOVE_MODE, NpcInfoType.PVP_FLAG);
if (summon.getHeading() > 0)
{
addComponentType(NpcInfoType.HEADING);
@@ -141,7 +141,7 @@ public class SummonInfo extends AbstractMaskPacket<NpcInfoType>
_allyId = summon.getOwner().getAppearance().getVisibleAllyCrestId();
addComponentType(NpcInfoType.CLAN);
}
addComponentType(NpcInfoType.COLOR_EFFECT);
addComponentType(NpcInfoType.PET_EVOLUTION_ID);
// TODO: Confirm me
if (summon.isInCombat())
{
@@ -241,9 +241,9 @@ public class SummonInfo extends AbstractMaskPacket<NpcInfoType>
{
writeInt(_summon.getHeading());
}
if (containsMask(NpcInfoType.UNKNOWN2))
if (containsMask(NpcInfoType.VEHICLE_ID))
{
writeInt(0); // Unknown
writeInt(0); // Vehicle object id.
}
if (containsMask(NpcInfoType.ATK_CAST_SPEED))
{
@@ -261,11 +261,11 @@ public class SummonInfo extends AbstractMaskPacket<NpcInfoType>
writeInt(_summon.getArmor()); // Armor id?
writeInt(0);
}
if (containsMask(NpcInfoType.ALIVE))
if (containsMask(NpcInfoType.STOP_MODE))
{
writeByte(!_summon.isDead());
}
if (containsMask(NpcInfoType.RUNNING))
if (containsMask(NpcInfoType.MOVE_MODE))
{
writeByte(_summon.isRunning());
}
@@ -289,9 +289,8 @@ public class SummonInfo extends AbstractMaskPacket<NpcInfoType>
{
writeInt(0); // Player ObjectId with Decoy
}
if (containsMask(NpcInfoType.COLOR_EFFECT))
if (containsMask(NpcInfoType.PET_EVOLUTION_ID))
{
// No visual effect
writeInt(0); // Unknown
}
if (containsMask(NpcInfoType.DISPLAY_EFFECT))
@@ -322,7 +321,7 @@ public class SummonInfo extends AbstractMaskPacket<NpcInfoType>
{
writeByte(_summon.isShowSummonAnimation() ? 2 : 0); // 2 - do some animation on spawn
}
if (containsMask(NpcInfoType.UNKNOWN12))
if (containsMask(NpcInfoType.FOLLOW_INFO))
{
writeInt(0);
writeInt(0);

View File

@@ -16,6 +16,7 @@
*/
package org.l2jmobius.gameserver.taskmanager;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -25,6 +26,7 @@ import org.l2jmobius.gameserver.ai.CtrlIntention;
import org.l2jmobius.gameserver.enums.Race;
import org.l2jmobius.gameserver.geoengine.GeoEngine;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.Party;
import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldObject;
import org.l2jmobius.gameserver.model.actor.Creature;
@@ -42,6 +44,7 @@ import org.l2jmobius.gameserver.util.Util;
public class AutoPlayTaskManager
{
private static final Set<Set<Player>> POOLS = ConcurrentHashMap.newKeySet();
private static final Map<Player, Integer> IDLE_COUNT = new ConcurrentHashMap<>();
private static final int POOL_SIZE = 300;
private static final int TASK_DELAY = 300;
@@ -96,6 +99,17 @@ public class AutoPlayTaskManager
// We take granted that mage classes do not auto hit.
if (isMageCaster(player))
{
// Logic adjustment for summons not attacking when in offline play.
if (player.isOfflinePlay() && player.hasSummon())
{
for (Summon summon : player.getServitors().values())
{
if (summon.hasAI() && !summon.isMoving() && !summon.isDisabled() && (summon.getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK) && (summon.getAI().getIntention() != CtrlIntention.AI_INTENTION_CAST) && creature.isAutoAttackable(player) && GeoEngine.getInstance().canSeeTarget(player, creature))
{
summon.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, creature);
}
}
}
continue PLAY;
}
@@ -121,23 +135,32 @@ public class AutoPlayTaskManager
final Weapon weapon = player.getActiveWeaponItem();
if (weapon != null)
{
final boolean ranged = weapon.getItemType().isRanged();
final double angle = Util.calculateHeadingFrom(player, creature);
final double radian = Math.toRadians(angle);
final double course = Math.toRadians(180);
final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + creature.getCollisionRadius()) * 2;
final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance);
final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance);
final Location location;
if (ranged)
final int idleCount = IDLE_COUNT.getOrDefault(player, 0);
if (idleCount > 10)
{
location = new Location(player.getX() + x1, player.getY() + y1, player.getZ());
final boolean ranged = weapon.getItemType().isRanged();
final double angle = Util.calculateHeadingFrom(player, creature);
final double radian = Math.toRadians(angle);
final double course = Math.toRadians(180);
final double distance = (ranged ? player.getCollisionRadius() : player.getCollisionRadius() + creature.getCollisionRadius()) * 2;
final int x1 = (int) (Math.cos(Math.PI + radian + course) * distance);
final int y1 = (int) (Math.sin(Math.PI + radian + course) * distance);
final Location location;
if (ranged)
{
location = new Location(player.getX() + x1, player.getY() + y1, player.getZ());
}
else
{
location = new Location(creature.getX() + x1, creature.getY() + y1, player.getZ());
}
player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location);
IDLE_COUNT.remove(player);
}
else
{
location = new Location(creature.getX() + x1, creature.getY() + y1, player.getZ());
IDLE_COUNT.put(player, idleCount + 1);
}
player.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, location);
}
}
}
@@ -145,6 +168,9 @@ public class AutoPlayTaskManager
}
}
// Reset idle count.
IDLE_COUNT.remove(player);
// Pickup.
if (player.getAutoPlaySettings().doPickup())
{
@@ -179,32 +205,55 @@ public class AutoPlayTaskManager
// Find target.
Creature creature = null;
double closestDistance = Double.MAX_VALUE;
TARGET: for (Creature nearby : World.getInstance().getVisibleObjectsInRange(player, Creature.class, player.getAutoPlaySettings().isShortRange() && (targetMode != 2 /* Characters */) ? 600 : 1400))
final Party party = player.getParty();
final Player leader = party == null ? null : party.getLeader();
if (Config.ENABLE_AUTO_ASSIST && (party != null) && (leader != null) && (leader != player) && !leader.isDead())
{
// Skip unavailable creatures.
if ((nearby == null) || nearby.isAlikeDead())
if (leader.calculateDistance3D(player) < (Config.ALT_PARTY_RANGE * 2 /* 2? */))
{
continue TARGET;
}
// Check creature target.
if (player.getAutoPlaySettings().isRespectfulHunting() && !nearby.isPlayable() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId()))
{
continue TARGET;
}
// Check next target mode.
if (!isTargetModeValid(targetMode, player, nearby))
{
continue TARGET;
}
// Check if creature is reachable.
if ((Math.abs(player.getZ() - nearby.getZ()) < 180) && GeoEngine.getInstance().canSeeTarget(player, nearby) && GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), nearby.getX(), nearby.getY(), nearby.getZ(), player.getInstanceWorld()))
{
final double creatureDistance = player.calculateDistance2D(nearby);
if (creatureDistance < closestDistance)
final WorldObject leaderTarget = leader.getTarget();
if ((leaderTarget != null) && (leaderTarget.isAttackable() || (leaderTarget.isPlayable() && !party.containsPlayer(leaderTarget.getActingPlayer()))))
{
creature = nearby;
closestDistance = creatureDistance;
creature = (Creature) leaderTarget;
}
else if ((player.getAI().getIntention() != CtrlIntention.AI_INTENTION_FOLLOW) && !player.isDisabled())
{
player.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, leader);
}
}
}
else
{
double closestDistance = Double.MAX_VALUE;
TARGET: for (Creature nearby : World.getInstance().getVisibleObjectsInRange(player, Creature.class, player.getAutoPlaySettings().isShortRange() && (targetMode != 2 /* Characters */) ? 600 : 1400))
{
// Skip unavailable creatures.
if ((nearby == null) || nearby.isAlikeDead())
{
continue TARGET;
}
// Check creature target.
if (player.getAutoPlaySettings().isRespectfulHunting() && !nearby.isPlayable() && (nearby.getTarget() != null) && (nearby.getTarget() != player) && !player.getServitors().containsKey(nearby.getTarget().getObjectId()))
{
continue TARGET;
}
// Check next target mode.
if (!isTargetModeValid(targetMode, player, nearby))
{
continue TARGET;
}
// Check if creature is reachable.
if ((Math.abs(player.getZ() - nearby.getZ()) < 180) && GeoEngine.getInstance().canSeeTarget(player, nearby) && GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), nearby.getX(), nearby.getY(), nearby.getZ(), player.getInstanceWorld()))
{
final double creatureDistance = player.calculateDistance2D(nearby);
if (creatureDistance < closestDistance)
{
creature = nearby;
closestDistance = creatureDistance;
}
}
}
}
@@ -310,6 +359,7 @@ public class AutoPlayTaskManager
{
player.getPet().followOwner();
}
IDLE_COUNT.remove(player);
return;
}
}

View File

@@ -35,7 +35,9 @@ import org.l2jmobius.gameserver.model.actor.Playable;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.actor.Summon;
import org.l2jmobius.gameserver.model.actor.instance.Guard;
import org.l2jmobius.gameserver.model.actor.transform.TransformTemplate;
import org.l2jmobius.gameserver.model.effects.AbstractEffect;
import org.l2jmobius.gameserver.model.effects.EffectType;
import org.l2jmobius.gameserver.model.events.EventDispatcher;
import org.l2jmobius.gameserver.model.events.EventType;
import org.l2jmobius.gameserver.model.events.impl.item.OnItemUse;
@@ -46,12 +48,12 @@ import org.l2jmobius.gameserver.model.item.ItemTemplate;
import org.l2jmobius.gameserver.model.item.instance.Item;
import org.l2jmobius.gameserver.model.skill.AbnormalType;
import org.l2jmobius.gameserver.model.skill.BuffInfo;
import org.l2jmobius.gameserver.model.skill.EffectScope;
import org.l2jmobius.gameserver.model.skill.Skill;
import org.l2jmobius.gameserver.model.skill.targets.AffectScope;
import org.l2jmobius.gameserver.model.skill.targets.TargetType;
import org.l2jmobius.gameserver.model.zone.ZoneId;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.ExBasicActionList;
/**
* @author Mobius
@@ -381,8 +383,9 @@ public class AutoUseTaskManager
// Do not allow to do some action if player is transformed.
if (player.isTransformed())
{
final int[] allowedActions = player.isTransformed() ? ExBasicActionList.ACTIONS_ON_TRANSFORM : ExBasicActionList.DEFAULT_ACTION_LIST;
if (Arrays.binarySearch(allowedActions, actionId) < 0)
final TransformTemplate transformTemplate = player.getTransformation().get().getTemplate(player);
final int[] allowedActions = transformTemplate.getBasicActionList();
if ((allowedActions == null) || (Arrays.binarySearch(allowedActions, actionId) < 0))
{
continue ACTIONS;
}
@@ -394,7 +397,24 @@ public class AutoUseTaskManager
final IPlayerActionHandler actionHandler = PlayerActionHandler.getInstance().getHandler(actionHolder.getHandler());
if (actionHandler != null)
{
actionHandler.useAction(player, actionHolder, false, false);
if (!actionHandler.isPetAction())
{
actionHandler.useAction(player, actionHolder, false, false);
}
else
{
final Summon summon = player.getAnyServitor();
if ((summon != null) && !summon.isAlikeDead())
{
final Skill skill = summon.getKnownSkill(actionHolder.getOptionId());
if ((skill != null) && !canSummonCastSkill(player, summon, skill))
{
continue ACTIONS;
}
actionHandler.useAction(player, actionHolder, false, false);
}
}
}
}
}
@@ -477,6 +497,59 @@ public class AutoUseTaskManager
return !player.isSkillDisabled(skill) && skill.checkCondition(player, target, false);
}
private boolean canSummonCastSkill(Player player, Summon summon, Skill skill)
{
if (skill.isBad() && (player.getTarget() == null))
{
return false;
}
final int mpConsume = skill.getMpConsume() + skill.getMpInitialConsume();
if ((((mpConsume != 0) && (mpConsume > (int) Math.floor(summon.getCurrentMp()))) || ((skill.getHpConsume() != 0) && (skill.getHpConsume() > (int) Math.floor(summon.getCurrentHp())))))
{
return false;
}
if (summon.isSkillDisabled(skill))
{
return false;
}
if (((player.getTarget() != null) && !skill.checkCondition(summon, player.getTarget(), false)) || ((player.getTarget() == null) && !skill.checkCondition(summon, player, false)))
{
return false;
}
if ((skill.getItemConsumeCount() > 0) && (summon.getInventory().getInventoryItemCount(skill.getItemConsumeId(), -1) < skill.getItemConsumeCount()))
{
return false;
}
if (skill.getTargetType().equals(TargetType.SELF) || skill.getTargetType().equals(TargetType.SUMMON))
{
final BuffInfo summonInfo = summon.getEffectList().getBuffInfoBySkillId(skill.getId());
return (summonInfo != null) && (summonInfo.getTime() >= REUSE_MARGIN_TIME);
}
if ((skill.getEffects(EffectScope.GENERAL) != null) && skill.getEffects(EffectScope.GENERAL).stream().anyMatch(a -> a.getEffectType().equals(EffectType.MANAHEAL_BY_LEVEL)) && (player.getCurrentMpPercent() > 80))
{
return false;
}
final BuffInfo buffInfo = player.getEffectList().getBuffInfoBySkillId(skill.getId());
final BuffInfo abnormalBuffInfo = player.getEffectList().getFirstBuffInfoByAbnormalType(skill.getAbnormalType());
if (abnormalBuffInfo != null)
{
if (buffInfo != null)
{
return (abnormalBuffInfo.getSkill().getId() == buffInfo.getSkill().getId()) && ((buffInfo.getTime() <= REUSE_MARGIN_TIME) || (buffInfo.getSkill().getLevel() < skill.getLevel()));
}
return (abnormalBuffInfo.getSkill().getAbnormalLevel() < skill.getAbnormalLevel()) || abnormalBuffInfo.isAbnormalType(AbnormalType.NONE);
}
return true;
}
}
public synchronized void startAutoUseTask(Player player)

View File

@@ -34,6 +34,7 @@ import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@@ -721,13 +722,13 @@ public class Util
{
if (descending)
{
return map.entrySet().stream().sorted(Map.Entry.comparingByValue(Collections.reverseOrder())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
return map.entrySet().stream().sorted(Entry.comparingByValue(Collections.reverseOrder())).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
return map.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
return map.entrySet().stream().sorted(Entry.comparingByValue()).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map)
{
return map.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
return map.entrySet().stream().sorted(Entry.comparingByValue()).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
}