Fishing rework based on L2jUnity free files.

Contributed by facab.
This commit is contained in:
MobiusDevelopment
2019-03-22 23:34:26 +00:00
parent bdeaab95bb
commit 9f72595ae0
314 changed files with 12904 additions and 7698 deletions

View File

@@ -1130,11 +1130,12 @@ public final class Config
public static float PREMIUM_RATE_DROP_AMOUNT;
public static float PREMIUM_RATE_SPOIL_CHANCE;
public static float PREMIUM_RATE_SPOIL_AMOUNT;
public static Map<Integer, Float> PREMIUM_RATE_DROP_CHANCE_BY_ID;
public static Map<Integer, Float> PREMIUM_RATE_DROP_AMOUNT_BY_ID;
public static boolean PREMIUM_HENNA_SLOT_ENABLED;
public static boolean PREMIUM_HENNA_SLOT_ENABLED_FOR_ALL;
public static boolean PREMIUM_HENNA_SLOT_ALL_DYES;
public static Map<Integer, Float> PREMIUM_RATE_DROP_CHANCE_BY_ID;
public static Map<Integer, Float> PREMIUM_RATE_DROP_AMOUNT_BY_ID;
public static boolean PREMIUM_ONLY_FISHING;
public static boolean PC_CAFE_ENABLED;
public static boolean PC_CAFE_ONLY_PREMIUM;
public static int PC_CAFE_MAX_POINTS;
@@ -2612,9 +2613,6 @@ public final class Config
PREMIUM_RATE_DROP_AMOUNT = PremiumSystem.getFloat("PremiumRateDropAmount", 1);
PREMIUM_RATE_SPOIL_CHANCE = PremiumSystem.getFloat("PremiumRateSpoilChance", 2);
PREMIUM_RATE_SPOIL_AMOUNT = PremiumSystem.getFloat("PremiumRateSpoilAmount", 1);
PREMIUM_HENNA_SLOT_ENABLED = PremiumSystem.getBoolean("EnablePremiumHennaSlot", true);
PREMIUM_HENNA_SLOT_ENABLED_FOR_ALL = PremiumSystem.getBoolean("EnablePremiumHennaSlotforNonPremium", true);
PREMIUM_HENNA_SLOT_ALL_DYES = PremiumSystem.getBoolean("EnableAnyHennaAtPremiumSlot", false);
final String[] premiumDropChanceMultiplier = PremiumSystem.getString("PremiumRateDropChanceByItemId", "").split(";");
PREMIUM_RATE_DROP_CHANCE_BY_ID = new HashMap<>(premiumDropChanceMultiplier.length);
if (!premiumDropChanceMultiplier[0].isEmpty())
@@ -2669,6 +2667,10 @@ public final class Config
}
}
}
PREMIUM_HENNA_SLOT_ENABLED = PremiumSystem.getBoolean("EnablePremiumHennaSlot", true);
PREMIUM_HENNA_SLOT_ENABLED_FOR_ALL = PremiumSystem.getBoolean("EnablePremiumHennaSlotforNonPremium", true);
PREMIUM_HENNA_SLOT_ALL_DYES = PremiumSystem.getBoolean("EnableAnyHennaAtPremiumSlot", false);
PREMIUM_ONLY_FISHING = PremiumSystem.getBoolean("PremiumOnlyFishing", true);
// Load PrivateStoreRange config file (if exists)
final PropertiesParser PrivateStoreRange = new PropertiesParser(CUSTOM_PRIVATE_STORE_RANGE_CONFIG_FILE);

View File

@@ -25,8 +25,12 @@ import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.gameserver.model.FishingBaitData;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.model.fishing.FishingBait;
import com.l2jmobius.gameserver.model.fishing.FishingCatch;
import com.l2jmobius.gameserver.model.fishing.FishingRod;
/**
* This class holds the Fishing information.
@@ -35,7 +39,8 @@ import com.l2jmobius.gameserver.model.FishingBaitData;
public final class FishingData implements IGameXmlReader
{
private static final Logger LOGGER = Logger.getLogger(FishingData.class.getName());
private final Map<Integer, FishingBaitData> _baitData = new HashMap<>();
private final Map<Integer, FishingBait> _baitData = new HashMap<>();
private final Map<Integer, FishingRod> _rodData = new HashMap<>();
private int _baitDistanceMin;
private int _baitDistanceMax;
private double _expRateMin;
@@ -56,7 +61,7 @@ public final class FishingData implements IGameXmlReader
{
_baitData.clear();
parseDatapackFile("data/Fishing.xml");
LOGGER.info(getClass().getSimpleName() + ": Loaded Fishing Data.");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _baitData.size() + " bait and " + _rodData.size() + " rod data.");
}
@Override
@@ -76,13 +81,13 @@ public final class FishingData implements IGameXmlReader
_baitDistanceMax = parseInteger(listItem.getAttributes(), "max");
break;
}
case "experienceRate":
case "xpRate":
{
_expRateMin = parseDouble(listItem.getAttributes(), "min");
_expRateMax = parseDouble(listItem.getAttributes(), "max");
break;
}
case "skillPointsRate":
case "spRate":
{
_spRateMin = parseDouble(listItem.getAttributes(), "min");
_spRateMax = parseDouble(listItem.getAttributes(), "max");
@@ -96,20 +101,39 @@ public final class FishingData implements IGameXmlReader
{
final NamedNodeMap attrs = bait.getAttributes();
final int itemId = parseInteger(attrs, "itemId");
final int level = parseInteger(attrs, "level");
final int minPlayerLevel = parseInteger(attrs, "minPlayerLevel");
final byte level = parseByte(attrs, "level", (byte) 1);
final byte minPlayerLevel = parseByte(attrs, "minPlayerLevel");
final byte maxPlayerLevel = parseByte(attrs, "minPlayerLevel", Config.PLAYER_MAXIMUM_LEVEL);
final double chance = parseDouble(attrs, "chance");
final int timeMin = parseInteger(attrs, "timeMin");
final int timeMax = parseInteger(attrs, "timeMax");
final int timeMax = parseInteger(attrs, "timeMax", timeMin);
final int waitMin = parseInteger(attrs, "waitMin");
final int waitMax = parseInteger(attrs, "waitMax");
final FishingBaitData baitData = new FishingBaitData(itemId, level, minPlayerLevel, chance, timeMin, timeMax, waitMin, waitMax);
final int waitMax = parseInteger(attrs, "waitMax", waitMin);
final boolean isPremiumOnly = parseBoolean(attrs, "isPremiumOnly", false);
if (ItemTable.getInstance().getTemplate(itemId) == null)
{
LOGGER.info(getClass().getSimpleName() + ": Could not find item with id " + itemId);
continue;
}
final FishingBait baitData = new FishingBait(itemId, level, minPlayerLevel, maxPlayerLevel, chance, timeMin, timeMax, waitMin, waitMax, isPremiumOnly);
for (Node c = bait.getFirstChild(); c != null; c = c.getNextSibling())
{
if ("catch".equalsIgnoreCase(c.getNodeName()))
{
baitData.addReward(parseInteger(c.getAttributes(), "itemId"));
final NamedNodeMap cAttrs = c.getAttributes();
final int cId = parseInteger(cAttrs, "itemId");
final float cChance = parseFloat(cAttrs, "chance");
final float cMultiplier = parseFloat(cAttrs, "multiplier", 1f);
if (ItemTable.getInstance().getTemplate(cId) == null)
{
LOGGER.info(getClass().getSimpleName() + ": Could not find item with id " + itemId);
continue;
}
baitData.addReward(new FishingCatch(cId, cChance, cMultiplier));
}
}
_baitData.put(baitData.getItemId(), baitData);
@@ -117,22 +141,44 @@ public final class FishingData implements IGameXmlReader
}
break;
}
case "rods":
{
for (Node rod = listItem.getFirstChild(); rod != null; rod = rod.getNextSibling())
{
if ("rod".equalsIgnoreCase(rod.getNodeName()))
{
final NamedNodeMap attrs = rod.getAttributes();
final int itemId = parseInteger(attrs, "itemId");
final int reduceFishingTime = parseInteger(attrs, "reduceFishingTime", 0);
final float xpMultiplier = parseFloat(attrs, "xpMultiplier", 1f);
final float spMultiplier = parseFloat(attrs, "spMultiplier", 1f);
if (ItemTable.getInstance().getTemplate(itemId) == null)
{
LOGGER.info(getClass().getSimpleName() + ": Could not find item with id " + itemId);
continue;
}
_rodData.put(itemId, new FishingRod(itemId, reduceFishingTime, xpMultiplier, spMultiplier));
}
}
}
}
}
}
}
}
/**
* Gets the fishing rod.
* @param baitItemId the item id
* @return A list of reward item ids
*/
public FishingBaitData getBaitData(int baitItemId)
public FishingBait getBaitData(int baitItemId)
{
return _baitData.get(baitItemId);
}
public FishingRod getRodData(int rodItemId)
{
return _rodData.get(rodItemId);
}
public int getBaitDistanceMin()
{
return _baitDistanceMin;

View File

@@ -120,7 +120,6 @@ import com.l2jmobius.gameserver.model.ArenaParticipantsHolder;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.ClanPrivilege;
import com.l2jmobius.gameserver.model.ClanWar;
import com.l2jmobius.gameserver.model.Fishing;
import com.l2jmobius.gameserver.model.L2AccessLevel;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2ClanMember;
@@ -208,6 +207,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerPvPCh
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerPvPKill;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerReputationChanged;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerSubChange;
import com.l2jmobius.gameserver.model.fishing.Fishing;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MovieHolder;
import com.l2jmobius.gameserver.model.holders.PlayerEventHolder;

View File

@@ -1,443 +1,471 @@
/*
* 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 com.l2jmobius.gameserver.model;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPool;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.enums.ShotType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerFishing;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.items.type.WeaponType;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.model.zone.type.L2FishingZone;
import com.l2jmobius.gameserver.model.zone.type.L2WaterZone;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExFishingEnd;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExFishingEnd.FishingEndReason;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExFishingEnd.FishingEndType;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExFishingStart;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExUserInfoFishing;
import com.l2jmobius.gameserver.util.Util;
/**
* @author bit
*/
public class Fishing
{
protected static final Logger LOGGER = Logger.getLogger(Fishing.class.getName());
private volatile ILocational _baitLocation = new Location(0, 0, 0);
private final L2PcInstance _player;
private ScheduledFuture<?> _reelInTask;
private ScheduledFuture<?> _startFishingTask;
private boolean _isFishing = false;
public Fishing(L2PcInstance player)
{
_player = player;
}
public synchronized boolean isFishing()
{
return _isFishing;
}
public boolean isAtValidLocation()
{
// TODO: implement checking direction
// if (calculateBaitLocation() == null)
// {
// return false;
// }
return _player.isInsideZone(ZoneId.FISHING);
}
public boolean canFish()
{
return !_player.isDead() && !_player.isAlikeDead() && !_player.hasBlockActions() && !_player.isSitting();
}
private FishingBaitData getCurrentBaitData()
{
final L2ItemInstance bait = _player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
return bait != null ? FishingData.getInstance().getBaitData(bait.getId()) : null;
}
private void cancelTasks()
{
if (_reelInTask != null)
{
_reelInTask.cancel(false);
_reelInTask = null;
}
if (_startFishingTask != null)
{
_startFishingTask.cancel(false);
_startFishingTask = null;
}
}
public synchronized void startFishing()
{
if (_isFishing)
{
return;
}
_isFishing = true;
castLine();
}
private void castLine()
{
if (!Config.ALLOW_FISHING && !_player.canOverrideCond(PcCondOverride.ZONE_CONDITIONS))
{
_player.sendMessage("Fishing is disabled.");
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
cancelTasks();
if (!canFish())
{
if (_isFishing)
{
_player.sendPacket(SystemMessageId.YOUR_ATTEMPT_AT_FISHING_HAS_BEEN_CANCELLED);
}
stopFishing(FishingEndType.ERROR);
return;
}
final FishingBaitData baitData = getCurrentBaitData();
final int minPlayerLevel = baitData == null ? 85 : baitData.getMinPlayerLevel();
if (_player.getLevel() < minPlayerLevel)
{
if (minPlayerLevel == 85)
{
_player.sendMessage("Fishing is available to characters Lv. 85 or above.");
}
else // In case of custom fishing level.
{
_player.sendMessage("You do not meet the fishing level requirements.");
}
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
final L2ItemInstance rod = _player.getActiveWeaponInstance();
if ((rod == null) || (rod.getItemType() != WeaponType.FISHINGROD))
{
_player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_A_FISHING_POLE_EQUIPPED);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
if (baitData == null)
{
_player.sendPacket(SystemMessageId.YOU_MUST_PUT_BAIT_ON_YOUR_HOOK_BEFORE_YOU_CAN_FISH);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
if (_player.isTransformed() || _player.isInBoat())
{
_player.sendPacket(SystemMessageId.YOU_CANNOT_FISH_WHEN_TRANSFORMED_OR_WHILE_RIDING_AS_A_PASSENGER_OF_A_BOAT_IT_S_AGAINST_THE_RULES);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
if (_player.isCrafting() || _player.isInStoreMode())
{
_player.sendPacket(SystemMessageId.YOU_CANNOT_FISH_WHILE_USING_A_RECIPE_BOOK_PRIVATE_WORKSHOP_OR_PRIVATE_STORE);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
if (_player.isInsideZone(ZoneId.WATER) || _player.isInWater())
{
_player.sendPacket(SystemMessageId.YOU_CANNOT_FISH_WHILE_UNDER_WATER);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
_baitLocation = calculateBaitLocation();
if (!_player.isInsideZone(ZoneId.FISHING) || (_baitLocation == null))
{
if (_isFishing)
{
// _player.sendPacket(SystemMessageId.YOUR_ATTEMPT_AT_FISHING_HAS_BEEN_CANCELLED);
_player.sendPacket(ActionFailed.STATIC_PACKET);
}
else
{
_player.sendPacket(SystemMessageId.YOU_CAN_T_FISH_HERE);
_player.sendPacket(ActionFailed.STATIC_PACKET);
}
stopFishing(FishingEndType.ERROR);
return;
}
if (!_player.isChargedShot(ShotType.FISH_SOULSHOTS))
{
_player.rechargeShots(false, false, true);
}
_reelInTask = ThreadPool.schedule(() ->
{
_player.getFishing().reelInWithReward();
_startFishingTask = ThreadPool.schedule(() -> _player.getFishing().castLine(), Rnd.get(baitData.getWaitMin(), baitData.getWaitMax()));
}, Rnd.get(baitData.getTimeMin(), baitData.getTimeMax()));
_player.stopMove(null);
_player.broadcastPacket(new ExFishingStart(_player, -1, baitData.getLevel(), _baitLocation));
_player.sendPacket(new ExUserInfoFishing(_player, true, _baitLocation));
_player.sendPacket(new PlaySound("SF_P_01"));
_player.sendPacket(SystemMessageId.YOU_CAST_YOUR_LINE_AND_START_TO_FISH);
}
public void reelInWithReward()
{
// Fish may or may not eat the hook. If it does - it consumes fishing bait and fishing shot.
// Then player may or may not catch the fish. Using fishing shots increases chance to win.
final FishingBaitData baitData = getCurrentBaitData();
if (baitData == null)
{
reelIn(FishingEndReason.LOSE, false);
LOGGER.warning("Player " + _player + " is fishing with unhandled bait: " + _player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND));
return;
}
double chance = baitData.getChance();
if (_player.isChargedShot(ShotType.FISH_SOULSHOTS))
{
chance *= 1.5; // +50 % chance to win
}
if (Rnd.get(0, 100) <= chance)
{
reelIn(FishingEndReason.WIN, true);
}
else
{
reelIn(FishingEndReason.LOSE, true);
}
}
private void reelIn(FishingEndReason reason, boolean consumeBait)
{
if (!_isFishing)
{
return;
}
cancelTasks();
try
{
final L2ItemInstance bait = _player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
if (consumeBait)
{
if ((bait == null) || !_player.getInventory().updateItemCount(null, bait, -1, _player, null))
{
reason = FishingEndReason.LOSE; // no bait - no reward
return;
}
}
if ((reason == FishingEndReason.WIN) && (bait != null))
{
final FishingBaitData baitData = FishingData.getInstance().getBaitData(bait.getId());
final int numRewards = baitData.getRewards().size();
if (numRewards > 0)
{
final FishingData fishingData = FishingData.getInstance();
final int lvlModifier = _player.getLevel() * _player.getLevel();
_player.addExpAndSp(Rnd.get(fishingData.getExpRateMin(), fishingData.getExpRateMax()) * lvlModifier, Rnd.get(fishingData.getSpRateMin(), fishingData.getSpRateMax()) * lvlModifier, true);
final int fishId = baitData.getRewards().get(Rnd.get(0, numRewards - 1));
_player.getInventory().addItem("Fishing Reward", fishId, 1, _player, null);
final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1);
msg.addItemName(fishId);
_player.sendPacket(msg);
_player.unchargeShot(ShotType.FISH_SOULSHOTS);
_player.rechargeShots(false, false, true);
}
else
{
LOGGER.log(Level.WARNING, "Could not find fishing rewards for bait ", bait.getId());
}
}
else if (reason == FishingEndReason.LOSE)
{
_player.sendPacket(SystemMessageId.THE_BAIT_HAS_BEEN_LOST_BECAUSE_THE_FISH_GOT_AWAY);
}
if (consumeBait)
{
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerFishing(_player, reason), _player);
}
}
finally
{
_player.broadcastPacket(new ExFishingEnd(_player, reason));
_player.sendPacket(new ExUserInfoFishing(_player, false));
}
}
public void stopFishing()
{
stopFishing(FishingEndType.PLAYER_STOP);
}
public synchronized void stopFishing(FishingEndType endType)
{
if (_isFishing)
{
reelIn(FishingEndReason.STOP, false);
_isFishing = false;
switch (endType)
{
case PLAYER_STOP:
{
_player.sendPacket(SystemMessageId.YOU_REEL_YOUR_LINE_IN_AND_STOP_FISHING);
break;
}
case PLAYER_CANCEL:
{
_player.sendPacket(SystemMessageId.YOUR_ATTEMPT_AT_FISHING_HAS_BEEN_CANCELLED);
break;
}
}
}
}
public ILocational getBaitLocation()
{
return _baitLocation;
}
private Location calculateBaitLocation()
{
// calculate a position in front of the player with a random distance
final int distMin = FishingData.getInstance().getBaitDistanceMin();
final int distMax = FishingData.getInstance().getBaitDistanceMax();
int distance = Rnd.get(distMin, distMax);
final double angle = Util.convertHeadingToDegree(_player.getHeading());
final double radian = Math.toRadians(angle);
final double sin = Math.sin(radian);
final double cos = Math.cos(radian);
int baitX = (int) (_player.getX() + (cos * distance));
int baitY = (int) (_player.getY() + (sin * distance));
// search for fishing zone
L2FishingZone fishingZone = null;
for (L2ZoneType zone : ZoneManager.getInstance().getZones(_player))
{
if (zone instanceof L2FishingZone)
{
fishingZone = (L2FishingZone) zone;
break;
}
}
// search for water zone
L2WaterZone waterZone = null;
for (L2ZoneType zone : ZoneManager.getInstance().getZones(baitX, baitY))
{
if (zone instanceof L2WaterZone)
{
waterZone = (L2WaterZone) zone;
break;
}
}
int baitZ = computeBaitZ(_player, baitX, baitY, fishingZone, waterZone);
if (baitZ == Integer.MIN_VALUE)
{
_player.sendPacket(SystemMessageId.YOU_CAN_T_FISH_HERE);
return null;
}
return new Location(baitX, baitY, baitZ);
}
/**
* Computes the Z of the bait.
* @param player the player
* @param baitX the bait x
* @param baitY the bait y
* @param fishingZone the fishing zone
* @param waterZone the water zone
* @return the bait z or {@link Integer#MIN_VALUE} when you cannot fish here
*/
private static int computeBaitZ(L2PcInstance player, int baitX, int baitY, L2FishingZone fishingZone, L2WaterZone waterZone)
{
if ((fishingZone == null))
{
return Integer.MIN_VALUE;
}
if ((waterZone == null))
{
return Integer.MIN_VALUE;
}
// always use water zone, fishing zone high z is high in the air...
final int baitZ = waterZone.getWaterZ();
// if (!GeoEngine.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ))
//
// return Integer.MIN_VALUE;
// }
if (GeoEngine.getInstance().hasGeo(baitX, baitY))
{
if (GeoEngine.getInstance().getHeight(baitX, baitY, baitZ) > baitZ)
{
return Integer.MIN_VALUE;
}
if (GeoEngine.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ)
{
return Integer.MIN_VALUE;
}
}
return baitZ;
}
}
/*
* 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 com.l2jmobius.gameserver.model.fishing;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPool;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.enums.ShotType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.PcCondOverride;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerFishing;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.items.type.WeaponType;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.model.zone.type.L2FishingZone;
import com.l2jmobius.gameserver.model.zone.type.L2WaterZone;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.PlaySound;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExFishingEnd;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExFishingEnd.FishingEndReason;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExFishingEnd.FishingEndType;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExFishingStart;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExUserInfoFishing;
import com.l2jmobius.gameserver.util.Util;
/**
* @author bit
*/
public class Fishing
{
protected static final Logger LOGGER = Logger.getLogger(Fishing.class.getName());
private volatile ILocational _baitLocation = new Location(0, 0, 0);
private final L2PcInstance _player;
private ScheduledFuture<?> _reelInTask;
private ScheduledFuture<?> _startFishingTask;
private boolean _isFishing = false;
public Fishing(L2PcInstance player)
{
_player = player;
}
public synchronized boolean isFishing()
{
return _isFishing;
}
public boolean isAtValidLocation()
{
// TODO: implement checking direction
// if (calculateBaitLocation() == null)
// {
// return false;
// }
return _player.isInsideZone(ZoneId.FISHING);
}
public boolean canFish()
{
return !_player.isDead() && !_player.isAlikeDead() && !_player.hasBlockActions() && !_player.isSitting();
}
private FishingBait getCurrentBaitData()
{
final L2ItemInstance bait = _player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
return bait != null ? FishingData.getInstance().getBaitData(bait.getId()) : null;
}
private void cancelTasks()
{
if (_reelInTask != null)
{
_reelInTask.cancel(false);
_reelInTask = null;
}
if (_startFishingTask != null)
{
_startFishingTask.cancel(false);
_startFishingTask = null;
}
}
public synchronized void startFishing()
{
if (_isFishing)
{
return;
}
_isFishing = true;
castLine();
}
private void castLine()
{
if (!Config.ALLOW_FISHING && !_player.canOverrideCond(PcCondOverride.ZONE_CONDITIONS))
{
_player.sendMessage("Fishing is disabled.");
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
cancelTasks();
if (!canFish())
{
if (_isFishing)
{
_player.sendPacket(SystemMessageId.YOUR_ATTEMPT_AT_FISHING_HAS_BEEN_CANCELLED);
}
stopFishing(FishingEndType.ERROR);
return;
}
final FishingBait baitData = getCurrentBaitData();
if (baitData == null)
{
_player.sendPacket(SystemMessageId.YOU_MUST_PUT_BAIT_ON_YOUR_HOOK_BEFORE_YOU_CAN_FISH);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
if (Config.PREMIUM_SYSTEM_ENABLED)
{
if (Config.PREMIUM_ONLY_FISHING && !_player.hasPremiumStatus())
{
_player.sendMessage("Fishing is available to premium users only.");
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
if (baitData.isPremiumOnly() && !_player.hasPremiumStatus())
{
_player.sendPacket(SystemMessageId.FAILED_PLEASE_TRY_AGAIN_USING_THE_CORRECT_BAIT);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
}
final int minPlayerLevel = baitData.getMinPlayerLevel();
final int maxPLayerLevel = baitData.getMaxPlayerLevel();
if ((_player.getLevel() < minPlayerLevel) && (_player.getLevel() > maxPLayerLevel))
{
_player.sendMessage("You do not meet the fishing level requirements.");
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
final L2ItemInstance rod = _player.getActiveWeaponInstance();
if ((rod == null) || (rod.getItemType() != WeaponType.FISHINGROD))
{
_player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_A_FISHING_POLE_EQUIPPED);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
final FishingRod rodData = FishingData.getInstance().getRodData(rod.getId());
if (rodData == null)
{
_player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_A_FISHING_POLE_EQUIPPED);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
if (_player.isTransformed() || _player.isInBoat())
{
_player.sendPacket(SystemMessageId.YOU_CANNOT_FISH_WHEN_TRANSFORMED_OR_WHILE_RIDING_AS_A_PASSENGER_OF_A_BOAT_IT_S_AGAINST_THE_RULES);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
if (_player.isCrafting() || _player.isInStoreMode())
{
_player.sendPacket(SystemMessageId.YOU_CANNOT_FISH_WHILE_USING_A_RECIPE_BOOK_PRIVATE_WORKSHOP_OR_PRIVATE_STORE);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
if (_player.isInsideZone(ZoneId.WATER) || _player.isInWater())
{
_player.sendPacket(SystemMessageId.YOU_CANNOT_FISH_WHILE_UNDER_WATER);
_player.sendPacket(ActionFailed.STATIC_PACKET);
stopFishing(FishingEndType.ERROR);
return;
}
_baitLocation = calculateBaitLocation();
if (!_player.isInsideZone(ZoneId.FISHING) || (_baitLocation == null))
{
if (_isFishing)
{
// _player.sendPacket(SystemMessageId.YOUR_ATTEMPT_AT_FISHING_HAS_BEEN_CANCELLED);
_player.sendPacket(ActionFailed.STATIC_PACKET);
}
else
{
_player.sendPacket(SystemMessageId.YOU_CAN_T_FISH_HERE);
_player.sendPacket(ActionFailed.STATIC_PACKET);
}
stopFishing(FishingEndType.ERROR);
return;
}
if (!_player.isChargedShot(ShotType.FISH_SOULSHOTS))
{
_player.rechargeShots(false, false, true);
}
final long fishingTime = Math.max(Rnd.get(baitData.getTimeMin(), baitData.getTimeMax()) - rodData.getReduceFishingTime(), 1000);
final long fishingWaitTime = Rnd.get(baitData.getWaitMin(), baitData.getWaitMax());
_reelInTask = ThreadPool.schedule(() ->
{
_player.getFishing().reelInWithReward();
_startFishingTask = ThreadPool.schedule(() -> _player.getFishing().castLine(), fishingWaitTime);
}, fishingTime);
_player.stopMove(null);
_player.broadcastPacket(new ExFishingStart(_player, -1, _baitLocation));
_player.sendPacket(new ExUserInfoFishing(_player, true, _baitLocation));
_player.sendPacket(new PlaySound("SF_P_01"));
_player.sendPacket(SystemMessageId.YOU_CAST_YOUR_LINE_AND_START_TO_FISH);
}
public void reelInWithReward()
{
// Fish may or may not eat the hook. If it does - it consumes fishing bait and fishing shot.
// Then player may or may not catch the fish. Using fishing shots increases chance to win.
final FishingBait baitData = getCurrentBaitData();
if (baitData == null)
{
reelIn(FishingEndReason.LOSE, false);
LOGGER.warning("Player " + _player + " is fishing with unhandled bait: " + _player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND));
return;
}
double chance = baitData.getChance();
if (_player.isChargedShot(ShotType.FISH_SOULSHOTS))
{
chance *= 2;
}
if (Rnd.get(100) <= chance)
{
reelIn(FishingEndReason.WIN, true);
}
else
{
reelIn(FishingEndReason.LOSE, true);
}
}
private void reelIn(FishingEndReason reason, boolean consumeBait)
{
if (!_isFishing)
{
return;
}
cancelTasks();
try
{
final L2ItemInstance bait = _player.getInventory().getPaperdollItem(Inventory.PAPERDOLL_LHAND);
if (consumeBait)
{
if ((bait == null) || !_player.getInventory().updateItemCount(null, bait, -1, _player, null))
{
reason = FishingEndReason.LOSE; // no bait - no reward
return;
}
}
if ((reason == FishingEndReason.WIN) && (bait != null))
{
final FishingBait baitData = FishingData.getInstance().getBaitData(bait.getId());
final FishingCatch fishingCatchData = baitData.getRandom();
if (fishingCatchData != null)
{
final FishingData fishingData = FishingData.getInstance();
final double lvlModifier = (Math.pow(_player.getLevel(), 2.2) * fishingCatchData.getMultiplier());
final long xp = (long) (Rnd.get(fishingData.getExpRateMin(), fishingData.getExpRateMax()) * lvlModifier);
final long sp = (long) (Rnd.get(fishingData.getSpRateMin(), fishingData.getSpRateMax()) * lvlModifier);
_player.addExpAndSp(xp, sp, true);
_player.getInventory().addItem("Fishing Reward", fishingCatchData.getItemId(), 1, _player, null);
final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1);
msg.addItemName(fishingCatchData.getItemId());
_player.sendPacket(msg);
_player.unchargeShot(ShotType.FISH_SOULSHOTS);
_player.rechargeShots(false, false, true);
}
else
{
LOGGER.log(Level.WARNING, "Could not find fishing rewards for bait ", bait.getId());
}
}
else if (reason == FishingEndReason.LOSE)
{
_player.sendPacket(SystemMessageId.THE_BAIT_HAS_BEEN_LOST_BECAUSE_THE_FISH_GOT_AWAY);
}
if (consumeBait)
{
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerFishing(_player, reason), _player);
}
}
finally
{
_player.broadcastPacket(new ExFishingEnd(_player, reason));
_player.sendPacket(new ExUserInfoFishing(_player, false));
}
}
public void stopFishing()
{
stopFishing(FishingEndType.PLAYER_STOP);
}
public synchronized void stopFishing(FishingEndType endType)
{
if (_isFishing)
{
reelIn(FishingEndReason.STOP, false);
_isFishing = false;
switch (endType)
{
case PLAYER_STOP:
{
_player.sendPacket(SystemMessageId.YOU_REEL_YOUR_LINE_IN_AND_STOP_FISHING);
break;
}
case PLAYER_CANCEL:
{
_player.sendPacket(SystemMessageId.YOUR_ATTEMPT_AT_FISHING_HAS_BEEN_CANCELLED);
break;
}
}
}
}
public ILocational getBaitLocation()
{
return _baitLocation;
}
private Location calculateBaitLocation()
{
// calculate a position in front of the player with a random distance
final int distMin = FishingData.getInstance().getBaitDistanceMin();
final int distMax = FishingData.getInstance().getBaitDistanceMax();
int distance = Rnd.get(distMin, distMax);
final double angle = Util.convertHeadingToDegree(_player.getHeading());
final double radian = Math.toRadians(angle);
final double sin = Math.sin(radian);
final double cos = Math.cos(radian);
int baitX = (int) (_player.getX() + (cos * distance));
int baitY = (int) (_player.getY() + (sin * distance));
// search for fishing zone
L2FishingZone fishingZone = null;
for (L2ZoneType zone : ZoneManager.getInstance().getZones(_player))
{
if (zone instanceof L2FishingZone)
{
fishingZone = (L2FishingZone) zone;
break;
}
}
// search for water zone
L2WaterZone waterZone = null;
for (L2ZoneType zone : ZoneManager.getInstance().getZones(baitX, baitY))
{
if (zone instanceof L2WaterZone)
{
waterZone = (L2WaterZone) zone;
break;
}
}
int baitZ = computeBaitZ(_player, baitX, baitY, fishingZone, waterZone);
if (baitZ == Integer.MIN_VALUE)
{
_player.sendPacket(SystemMessageId.YOU_CAN_T_FISH_HERE);
return null;
}
return new Location(baitX, baitY, baitZ);
}
/**
* Computes the Z of the bait.
* @param player the player
* @param baitX the bait x
* @param baitY the bait y
* @param fishingZone the fishing zone
* @param waterZone the water zone
* @return the bait z or {@link Integer#MIN_VALUE} when you cannot fish here
*/
private static int computeBaitZ(L2PcInstance player, int baitX, int baitY, L2FishingZone fishingZone, L2WaterZone waterZone)
{
if ((fishingZone == null))
{
return Integer.MIN_VALUE;
}
if ((waterZone == null))
{
return Integer.MIN_VALUE;
}
// always use water zone, fishing zone high z is high in the air...
final int baitZ = waterZone.getWaterZ();
// if (!GeoEngine.getInstance().canSeeTarget(player.getX(), player.getY(), player.getZ(), baitX, baitY, baitZ))
//
// return Integer.MIN_VALUE;
// }
if (GeoEngine.getInstance().hasGeo(baitX, baitY))
{
if (GeoEngine.getInstance().getHeight(baitX, baitY, baitZ) > baitZ)
{
return Integer.MIN_VALUE;
}
if (GeoEngine.getInstance().getHeight(baitX, baitY, player.getZ()) > baitZ)
{
return Integer.MIN_VALUE;
}
}
return baitZ;
}
}

View File

@@ -1,98 +1,128 @@
/*
* 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 com.l2jmobius.gameserver.model;
import java.util.ArrayList;
import java.util.List;
/**
* @author bit
*/
public class FishingBaitData
{
private final int _itemId;
private final int _level;
private final int _minPlayerLevel;
private final double _chance;
private final int _timeMin;
private final int _timeMax;
private final int _waitMin;
private final int _waitMax;
private final List<Integer> _rewards = new ArrayList<>();
public FishingBaitData(int itemId, int level, int minPlayerLevel, double chance, int timeMin, int timeMax, int waitMin, int waitMax)
{
_itemId = itemId;
_level = level;
_minPlayerLevel = minPlayerLevel;
_chance = chance;
_timeMin = timeMin;
_timeMax = timeMax;
_waitMin = waitMin;
_waitMax = waitMax;
}
public int getItemId()
{
return _itemId;
}
public int getLevel()
{
return _level;
}
public int getMinPlayerLevel()
{
return _minPlayerLevel;
}
public double getChance()
{
return _chance;
}
public int getTimeMin()
{
return _timeMin;
}
public int getTimeMax()
{
return _timeMax;
}
public int getWaitMin()
{
return _waitMin;
}
public int getWaitMax()
{
return _waitMax;
}
public List<Integer> getRewards()
{
return _rewards;
}
public void addReward(int itemId)
{
_rewards.add(itemId);
}
}
/*
* 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 com.l2jmobius.gameserver.model.fishing;
import java.util.ArrayList;
import java.util.List;
import com.l2jmobius.commons.util.Rnd;
/**
* @author bit
*/
public class FishingBait
{
private final int _itemId;
private final byte _level;
private final byte _minPlayerLevel;
private final byte _maxPlayerLevel;
private final double _chance;
private final int _timeMin;
private final int _timeMax;
private final int _waitMin;
private final int _waitMax;
private final boolean _isPremiumOnly;
private final List<FishingCatch> _rewards = new ArrayList<>();
public FishingBait(int itemId, byte level, byte minPlayerLevel, byte maxPlayerLevel, double chance, int timeMin, int timeMax, int waitMin, int waitMax, boolean isPremiumOnly)
{
_itemId = itemId;
_level = level;
_minPlayerLevel = minPlayerLevel;
_maxPlayerLevel = maxPlayerLevel;
_chance = chance;
_timeMin = timeMin;
_timeMax = timeMax;
_waitMin = waitMin;
_waitMax = waitMax;
_isPremiumOnly = isPremiumOnly;
}
public int getItemId()
{
return _itemId;
}
public byte getLevel()
{
return _level;
}
public byte getMinPlayerLevel()
{
return _minPlayerLevel;
}
public byte getMaxPlayerLevel()
{
return _maxPlayerLevel;
}
public double getChance()
{
return _chance;
}
public int getTimeMin()
{
return _timeMin;
}
public int getTimeMax()
{
return _timeMax;
}
public int getWaitMin()
{
return _waitMin;
}
public int getWaitMax()
{
return _waitMax;
}
public boolean isPremiumOnly()
{
return _isPremiumOnly;
}
public List<FishingCatch> getRewards()
{
return _rewards;
}
public void addReward(FishingCatch catchData)
{
_rewards.add(catchData);
}
public FishingCatch getRandom()
{
float random = Rnd.get(100);
for (FishingCatch fishingCatchData : _rewards)
{
if (fishingCatchData.getChance() > random)
{
return fishingCatchData;
}
random -= fishingCatchData.getChance();
}
return null;
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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 com.l2jmobius.gameserver.model.fishing;
/**
* @author Zarcos
*/
public class FishingCatch
{
private final int _itemId;
private final float _chance;
private final float _multiplier;
public FishingCatch(int itemId, float chance, float multiplier)
{
_itemId = itemId;
_chance = chance;
_multiplier = multiplier;
}
public int getItemId()
{
return _itemId;
}
public float getChance()
{
return _chance;
}
public float getMultiplier()
{
return _multiplier;
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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 com.l2jmobius.gameserver.model.fishing;
/**
* @author Zarcos
*/
public class FishingRod
{
private final int _itemId;
private final int _reduceFishingTime;
private final float _xpMultiplier;
private final float _spMultiplier;
public FishingRod(int itemId, int reduceFishingTime, float xpMultiplier, float spMultiplier)
{
_itemId = itemId;
_reduceFishingTime = reduceFishingTime;
_xpMultiplier = xpMultiplier;
_spMultiplier = spMultiplier;
}
public int getItemId()
{
return _itemId;
}
public int getReduceFishingTime()
{
return _reduceFishingTime;
}
public float getXpMultiplier()
{
return _xpMultiplier;
}
public float getSpMultiplier()
{
return _spMultiplier;
}
}

View File

@@ -20,10 +20,10 @@ import java.lang.ref.WeakReference;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPool;
import com.l2jmobius.gameserver.model.Fishing;
import com.l2jmobius.gameserver.model.PcCondOverride;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.fishing.Fishing;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.serverpackets.fishing.ExAutoFishAvailable;

View File

@@ -29,20 +29,17 @@ public class ExFishingStart implements IClientOutgoingPacket
{
private final L2PcInstance _player;
private final int _fishType;
private final int _baitType;
private final ILocational _baitLocation;
/**
* @param player
* @param fishType
* @param baitType - 0 = newbie, 1 = normal, 2 = night
* @param baitLocation
*/
public ExFishingStart(L2PcInstance player, int fishType, int baitType, ILocational baitLocation)
public ExFishingStart(L2PcInstance player, int fishType, ILocational baitLocation)
{
_player = player;
_fishType = fishType;
_baitType = baitType;
_baitLocation = baitLocation;
}
@@ -55,7 +52,7 @@ public class ExFishingStart implements IClientOutgoingPacket
packet.writeD(_baitLocation.getX());
packet.writeD(_baitLocation.getY());
packet.writeD(_baitLocation.getZ());
packet.writeC(_baitType);
packet.writeC(0x01); // 0 = newbie, 1 = normal, 2 = night
return true;
}
}