/* * 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 . */ package com.l2jserver.gameserver.model; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.concurrent.ScheduledFuture; import java.util.logging.Level; import java.util.logging.Logger; import com.l2jserver.Config; import com.l2jserver.L2DatabaseFactory; import com.l2jserver.gameserver.ThreadPoolManager; import com.l2jserver.gameserver.datatables.SkillTable; import com.l2jserver.gameserver.instancemanager.CursedWeaponsManager; import com.l2jserver.gameserver.instancemanager.TransformationManager; import com.l2jserver.gameserver.model.actor.L2Attackable; import com.l2jserver.gameserver.model.actor.L2Character; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.network.SystemMessageId; import com.l2jserver.gameserver.network.serverpackets.Earthquake; import com.l2jserver.gameserver.network.serverpackets.ExRedSky; import com.l2jserver.gameserver.network.serverpackets.InventoryUpdate; import com.l2jserver.gameserver.network.serverpackets.ItemList; import com.l2jserver.gameserver.network.serverpackets.SocialAction; import com.l2jserver.gameserver.network.serverpackets.SystemMessage; import com.l2jserver.gameserver.network.serverpackets.UserInfo; import com.l2jserver.gameserver.templates.item.L2Item; import com.l2jserver.gameserver.util.Broadcast; import com.l2jserver.gameserver.util.Point3D; import com.l2jserver.util.Rnd; public class CursedWeapon { private static final Logger _log = Logger.getLogger(CursedWeaponsManager.class.getName()); // _name is the name of the cursed weapon associated with its ID. private final String _name; // _itemId is the Item ID of the cursed weapon. private final int _itemId; // _skillId is the skills ID. private final int _skillId; private final int _skillMaxLevel; private int _dropRate; private int _duration; private int _durationLost; private int _disapearChance; private int _stageKills; // this should be false unless if the cursed weapon is dropped, in that case it would be true. private boolean _isDropped = false; // this sets the cursed weapon status to true only if a player has the cursed weapon, otherwise this should be false. private boolean _isActivated = false; private ScheduledFuture _removeTask; private int _nbKills = 0; private long _endTime = 0; private int _playerId = 0; protected L2PcInstance _player = null; private L2ItemInstance _item = null; private int _playerKarma = 0; private int _playerPkKills = 0; protected int transformationId = 0; private static final int[] TRANSFORM_IDS = new int[]{3630,3631}; // ========================================================= // Constructor public CursedWeapon(int itemId, int skillId, String name) { _name = name; _itemId = itemId; _skillId = skillId; _skillMaxLevel = SkillTable.getInstance().getMaxLevel(_skillId); } // ========================================================= // Private public void endOfLife() { if (_isActivated) { if (_player != null && _player.isOnline()) { // Remove from player _log.info(_name + " being removed online." ); _player.abortAttack(); _player.setKarma(_playerKarma); _player.setPkKills(_playerPkKills); _player.setCursedWeaponEquippedId(0); removeSkill(); // Remove _player.getInventory().unEquipItemInBodySlot(L2Item.SLOT_LR_HAND); _player.store(); // Destroy L2ItemInstance removedItem = _player.getInventory().destroyItemByItemId("", _itemId, 1, _player, null); if (!Config.FORCE_INVENTORY_UPDATE) { InventoryUpdate iu = new InventoryUpdate(); if (removedItem.getCount() == 0) iu.addRemovedItem(removedItem); else iu.addModifiedItem(removedItem); _player.sendPacket(iu); } else _player.sendPacket(new ItemList(_player, true)); _player.broadcastUserInfo(); } else { // Remove from Db _log.info(_name + " being removed offline." ); Connection con = null; try { con = L2DatabaseFactory.getInstance().getConnection(); // Delete the item PreparedStatement statement = con.prepareStatement("DELETE FROM items WHERE owner_id=? AND item_id=?"); statement.setInt(1, _playerId); statement.setInt(2, _itemId); if (statement.executeUpdate() != 1) { _log.warning("Error while deleting itemId "+ _itemId +" from userId "+ _playerId); } statement.close(); /* Yesod: Skill is not stored into database any more. // Delete the skill statement = con.prepareStatement("DELETE FROM character_skills WHERE charId=? AND skill_id=?"); statement.setInt(1, _playerId); statement.setInt(2, _skillId); if (statement.executeUpdate() != 1) { _log.warning("Error while deleting skillId "+ _skillId +" from userId "+_playerId); } */ // Restore the karma statement = con.prepareStatement("UPDATE characters SET karma=?, pkkills=? WHERE charId=?"); statement.setInt(1, _playerKarma); statement.setInt(2, _playerPkKills); statement.setInt(3, _playerId); if (statement.executeUpdate() != 1) { _log.warning("Error while updating karma & pkkills for userId "+_playerId); } statement.close(); } catch (Exception e) { _log.log(Level.WARNING, "Could not delete : " + e.getMessage(), e); } finally { L2DatabaseFactory.close(con); } } } else { // either this cursed weapon is in the inventory of someone who has another cursed weapon equipped, // OR this cursed weapon is on the ground. if ((_player != null) && (_player.getInventory().getItemByItemId(_itemId) != null)) { // Destroy L2ItemInstance removedItem = _player.getInventory().destroyItemByItemId("", _itemId, 1, _player, null); if (!Config.FORCE_INVENTORY_UPDATE) { InventoryUpdate iu = new InventoryUpdate(); if (removedItem.getCount() == 0) iu.addRemovedItem(removedItem); else iu.addModifiedItem(removedItem); _player.sendPacket(iu); } else _player.sendPacket(new ItemList(_player, true)); _player.broadcastUserInfo(); } // is dropped on the ground else if (_item != null) { _item.decayMe(); L2World.getInstance().removeObject(_item); _log.info(_name+" item has been removed from World."); } } // Delete infos from table if any CursedWeaponsManager.removeFromDb(_itemId); SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_DISAPPEARED); sm.addItemName(_itemId); CursedWeaponsManager.announce(sm); // Reset state cancelTask(); _isActivated = false; _isDropped = false; _endTime = 0; _player = null; _playerId = 0; _playerKarma = 0; _playerPkKills = 0; _item = null; _nbKills = 0; } private void cancelTask() { if (_removeTask != null) { _removeTask.cancel(true); _removeTask = null; } } private class RemoveTask implements Runnable { protected RemoveTask() { } public void run() { if (System.currentTimeMillis() >= getEndTime()) endOfLife(); } } private void dropIt(L2Attackable attackable, L2PcInstance player) { dropIt(attackable, player, null, true); } private void dropIt(L2Attackable attackable, L2PcInstance player, L2Character killer, boolean fromMonster) { _isActivated = false; if (fromMonster) { _item = attackable.dropItem(player, _itemId, 1); _item.setDropTime(0); // Prevent item from being removed by ItemsAutoDestroy // RedSky and Earthquake ExRedSky packet = new ExRedSky(10); Earthquake eq = new Earthquake(player.getX(), player.getY(), player.getZ(), 14, 3); Broadcast.toAllOnlinePlayers(packet); Broadcast.toAllOnlinePlayers(eq); } else { _item = _player.getInventory().getItemByItemId(_itemId); _player.dropItem("DieDrop", _item, killer, true); _player.setKarma(_playerKarma); _player.setPkKills(_playerPkKills); _player.setCursedWeaponEquippedId(0); removeSkill(); _player.abortAttack(); //L2ItemInstance item = _player.getInventory().getItemByItemId(_itemId); //_player.getInventory().dropItem("DieDrop", item, _player, null); //_player.getInventory().getItemByItemId(_itemId).dropMe(_player, _player.getX(), _player.getY(), _player.getZ()); } _isDropped = true; SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S2_WAS_DROPPED_IN_THE_S1_REGION); if (player != null) sm.addZoneName(player.getX(), player.getY(), player.getZ()); // Region Name else if (_player != null) sm.addZoneName(_player.getX(), _player.getY(), _player.getZ()); // Region Name else sm.addZoneName(killer.getX(), killer.getY(), killer.getZ()); // Region Name sm.addItemName(_itemId); CursedWeaponsManager.announce(sm); // in the Hot Spring region } public void cursedOnLogin() { doTransform(); giveSkill(); SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.S2_OWNER_HAS_LOGGED_INTO_THE_S1_REGION); msg.addZoneName(_player.getX(), _player.getY(), _player.getZ()); msg.addItemName(_player.getCursedWeaponEquippedId()); CursedWeaponsManager.announce(msg); CursedWeapon cw = CursedWeaponsManager.getInstance().getCursedWeapon(_player.getCursedWeaponEquippedId()); SystemMessage msg2 = SystemMessage.getSystemMessage(SystemMessageId.S2_MINUTE_OF_USAGE_TIME_ARE_LEFT_FOR_S1); int timeLeft = (int)(cw.getTimeLeft()/60000); msg2.addItemName(_player.getCursedWeaponEquippedId()); msg2.addNumber(timeLeft); _player.sendPacket(msg2); } /** * Yesod:
* Rebind the passive skill belonging to the CursedWeapon. Invoke this * method if the weapon owner switches to a subclass. */ public void giveSkill() { int level = 1+(_nbKills/_stageKills); if (level > _skillMaxLevel) level = _skillMaxLevel; L2Skill skill = SkillTable.getInstance().getInfo(_skillId, level); // Yesod: // To properly support subclasses this skill can not be stored. _player.addSkill(skill, false); // Void Burst, Void Flow skill = SkillTable.FrequentSkill.VOID_BURST.getSkill(); _player.addSkill(skill, false); skill = SkillTable.FrequentSkill.VOID_FLOW.getSkill(); _player.addSkill(skill, false); _player.setTransformAllowedSkills(TRANSFORM_IDS); if (Config.DEBUG) _log.info("Player "+_player.getName() +" has been awarded with skill "+skill); _player.sendSkillList(); } public void doTransform() { if (_itemId == 8689) { transformationId = 302; } else if (_itemId == 8190) { transformationId = 301; } if (_player.isTransformed() || _player.isInStance()) { _player.stopTransformation(true); ThreadPoolManager.getInstance().scheduleGeneral(new Runnable() { public void run() { TransformationManager.getInstance().transformPlayer(transformationId, _player); } }, 500); } else TransformationManager.getInstance().transformPlayer(transformationId, _player); } public void removeSkill() { _player.removeSkill(_skillId); _player.removeSkill(SkillTable.FrequentSkill.VOID_BURST.getSkill().getId()); _player.removeSkill(SkillTable.FrequentSkill.VOID_FLOW.getSkill().getId()); _player.untransform(); _player.sendSkillList(); } // ========================================================= // Public public void reActivate() { _isActivated = true; if (_endTime - System.currentTimeMillis() <= 0) endOfLife(); else _removeTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new RemoveTask(), _durationLost*12000L, _durationLost*12000L); } public boolean checkDrop(L2Attackable attackable, L2PcInstance player) { if (Rnd.get(100000) < _dropRate) { // Drop the item dropIt(attackable, player); // Start the Life Task _endTime = System.currentTimeMillis() + _duration * 60000L; _removeTask = ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new RemoveTask(), _durationLost*12000L, _durationLost*12000L); return true; } return false; } public void activate(L2PcInstance player, L2ItemInstance item) { // if the player is mounted, attempt to unmount first. Only allow picking up // the zariche if unmounting is successful. if (player.isMounted()) { if (!player.dismount()) { // TODO: correct this custom message. player.sendMessage("You may not pick up this item while riding in this territory"); player.dropItem("InvDrop", item, null, true); return; } } _isActivated = true; // Player holding it data _player = player; _playerId = _player.getObjectId(); _playerKarma = _player.getKarma(); _playerPkKills = _player.getPkKills(); saveData(); // Change player stats _player.setCursedWeaponEquippedId(_itemId); _player.setKarma(9999999); _player.setPkKills(0); if (_player.isInParty()) _player.getParty().removePartyMember(_player); // Disable All Skills // Do Transform doTransform(); // Add skill giveSkill(); // Equip with the weapon _item = item; //L2ItemInstance[] items = _player.getInventory().equipItem(_item); SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_EQUIPPED); sm.addItemName(_item); _player.sendPacket(sm); // Fully heal player _player.setCurrentHpMp(_player.getMaxHp(), _player.getMaxMp()); _player.setCurrentCp(_player.getMaxCp()); // Refresh inventory if (!Config.FORCE_INVENTORY_UPDATE) { InventoryUpdate iu = new InventoryUpdate(); iu.addItem(_item); //iu.addItems(Arrays.asList(items)); _player.sendPacket(iu); } else _player.sendPacket(new ItemList(_player, false)); // Refresh player stats _player.broadcastUserInfo(); SocialAction atk = new SocialAction(_player, 17); _player.broadcastPacket(atk); sm = SystemMessage.getSystemMessage(SystemMessageId.THE_OWNER_OF_S2_HAS_APPEARED_IN_THE_S1_REGION); sm.addZoneName(_player.getX(), _player.getY(), _player.getZ()); // Region Name sm.addItemName(_item); CursedWeaponsManager.announce(sm); } public void saveData() { if (Config.DEBUG) _log.info("CursedWeapon: Saving data to disk."); Connection con = null; try { con = L2DatabaseFactory.getInstance().getConnection(); // Delete previous datas PreparedStatement statement = con.prepareStatement("DELETE FROM cursed_weapons WHERE itemId = ?"); statement.setInt(1, _itemId); statement.executeUpdate(); if (_isActivated) { statement = con.prepareStatement("INSERT INTO cursed_weapons (itemId, charId, playerKarma, playerPkKills, nbKills, endTime) VALUES (?, ?, ?, ?, ?, ?)"); statement.setInt(1, _itemId); statement.setInt(2, _playerId); statement.setInt(3, _playerKarma); statement.setInt(4, _playerPkKills); statement.setInt(5, _nbKills); statement.setLong(6, _endTime); statement.executeUpdate(); statement.close(); } } catch (SQLException e) { _log.log(Level.SEVERE, "CursedWeapon: Failed to save data.", e); } finally { L2DatabaseFactory.close(con); } } public void dropIt(L2Character killer) { if (Rnd.get(100) <= _disapearChance) { // Remove it endOfLife(); } else { // Unequip & Drop dropIt(null, null, killer, false); // Reset player stats _player.setKarma(_playerKarma); _player.setPkKills(_playerPkKills); _player.setCursedWeaponEquippedId(0); removeSkill(); _player.abortAttack(); _player.broadcastUserInfo(); } } public void increaseKills() { _nbKills++; if (_player != null && _player.isOnline()) { _player.setPkKills(_nbKills); _player.sendPacket(new UserInfo(_player)); if (_nbKills % _stageKills == 0 && _nbKills <= _stageKills*(_skillMaxLevel-1)) { giveSkill(); } } // Reduce time-to-live _endTime -= _durationLost * 60000L; saveData(); } // ========================================================= // Setter public void setDisapearChance(int disapearChance) { _disapearChance = disapearChance; } public void setDropRate(int dropRate) { _dropRate = dropRate; } public void setDuration(int duration) { _duration = duration; } public void setDurationLost(int durationLost) { _durationLost = durationLost; } public void setStageKills(int stageKills) { _stageKills = stageKills; } public void setNbKills(int nbKills) { _nbKills = nbKills; } public void setPlayerId(int playerId) { _playerId = playerId; } public void setPlayerKarma(int playerKarma) { _playerKarma = playerKarma; } public void setPlayerPkKills(int playerPkKills) { _playerPkKills = playerPkKills; } public void setActivated(boolean isActivated) { _isActivated = isActivated; } public void setDropped(boolean isDropped) { _isDropped = isDropped; } public void setEndTime(long endTime) { _endTime = endTime; } public void setPlayer(L2PcInstance player) { _player = player; } public void setItem(L2ItemInstance item) { _item = item; } // ========================================================= // Getter public boolean isActivated() { return _isActivated; } public boolean isDropped() { return _isDropped; } public long getEndTime() { return _endTime; } public String getName() { return _name; } public int getItemId() { return _itemId; } public int getSkillId() { return _skillId; } public int getPlayerId() { return _playerId; } public L2PcInstance getPlayer() { return _player; } public int getPlayerKarma() { return _playerKarma; } public int getPlayerPkKills() { return _playerPkKills; } public int getNbKills() { return _nbKills; } public int getStageKills() { return _stageKills; } public boolean isActive() { return _isActivated || _isDropped; } public int getLevel() { if (_nbKills > _stageKills*_skillMaxLevel) { return _skillMaxLevel; } else { return (_nbKills / _stageKills); } } public long getTimeLeft() { return _endTime - System.currentTimeMillis(); } public void goTo(L2PcInstance player) { if (player == null) return; if (_isActivated && _player != null) { // Go to player holding the weapon player.teleToLocation(_player.getX(), _player.getY(), _player.getZ() + 20, true); } else if (_isDropped && _item != null) { // Go to item on the ground player.teleToLocation(_item.getX(), _item.getY(), _item.getZ() + 20, true); } else { player.sendMessage(_name+" isn't in the World."); } } public Point3D getWorldPosition() { if (_isActivated && _player != null) return _player.getPosition().getWorldPosition(); if (_isDropped && _item != null) return _item.getPosition().getWorldPosition(); return null; } public long getDuration() { return _duration; } }