Fishing rework based on L2jUnity free files.
Contributed by facab.
This commit is contained in:
@@ -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;
|
||||
|
@@ -122,7 +122,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;
|
||||
@@ -210,6 +209,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.AttendanceInfoHolder;
|
||||
import com.l2jmobius.gameserver.model.holders.ItemHolder;
|
||||
import com.l2jmobius.gameserver.model.holders.MovieHolder;
|
||||
|
@@ -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.sendPacket(SystemMessageId.FISHING_IS_AVAILABLE_TO_CHARACTERS_LV_85_OR_ABOVE);
|
||||
}
|
||||
else // In case of custom fishing level.
|
||||
{
|
||||
_player.sendPacket(SystemMessageId.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_YOUR_CHARACTER_IS_NOT_FACING_WATER_OR_YOU_ARE_NOT_IN_A_FISHING_GROUND);
|
||||
_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_YOUR_CHARACTER_IS_NOT_FACING_WATER_OR_YOU_ARE_NOT_IN_A_FISHING_GROUND);
|
||||
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.sendPacket(SystemMessageId.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_YOUR_CHARACTER_IS_NOT_FACING_WATER_OR_YOU_ARE_NOT_IN_A_FISHING_GROUND);
|
||||
_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_YOUR_CHARACTER_IS_NOT_FACING_WATER_OR_YOU_ARE_NOT_IN_A_FISHING_GROUND);
|
||||
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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user