/* * 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 silentium.gameserver.network.clientpackets; import gnu.trove.map.hash.TIntObjectHashMap; import silentium.gameserver.GameTimeController; import silentium.gameserver.ai.CtrlEvent; import silentium.gameserver.ai.CtrlIntention; import silentium.gameserver.ai.NextAction; import silentium.gameserver.ai.NextAction.NextActionCallback; import silentium.gameserver.ai.SummonAI; import silentium.gameserver.instancemanager.CastleManager; import silentium.gameserver.model.L2CharPosition; import silentium.gameserver.model.L2Object; import silentium.gameserver.model.L2Skill; import silentium.gameserver.model.actor.L2Character; import silentium.gameserver.model.actor.L2Summon; import silentium.gameserver.model.actor.instance.L2DoorInstance; import silentium.gameserver.model.actor.instance.L2PcInstance; import silentium.gameserver.model.actor.instance.L2PetInstance; import silentium.gameserver.model.actor.instance.L2SiegeSummonInstance; import silentium.gameserver.model.actor.instance.L2StaticObjectInstance; import silentium.gameserver.model.actor.instance.L2SummonInstance; import silentium.gameserver.network.SystemMessageId; import silentium.gameserver.network.serverpackets.ActionFailed; import silentium.gameserver.network.serverpackets.ChairSit; import silentium.gameserver.utils.Util; public final class RequestActionUse extends L2GameClientPacket { private int _actionId; private boolean _ctrlPressed; private boolean _shiftPressed; @Override protected void readImpl() { _actionId = readD(); _ctrlPressed = (readD() == 1); _shiftPressed = (readC() == 1); } @Override protected void runImpl() { final L2PcInstance activeChar = getClient().getActiveChar(); if (activeChar == null) return; log.debug(activeChar.getName() + " request Action use: id " + _actionId + " 2:" + _ctrlPressed + " 3:" + _shiftPressed); // dont do anything if player is dead, or use fakedeath using another action than sit. if ((activeChar.isFakeDeath() && _actionId != 0) || activeChar.isDead()) { activeChar.sendPacket(ActionFailed.STATIC_PACKET); return; } // don't do anything if player is confused if (activeChar.isOutOfControl()) { activeChar.sendPacket(ActionFailed.STATIC_PACKET); return; } L2Summon pet = activeChar.getPet(); L2Object target = activeChar.getTarget(); log.info("Requested Action ID: " + _actionId); switch (_actionId) { case 0: final L2PcInstance ch = activeChar; final L2Object targ = target; if (activeChar.getMountType() != 0) break; if (activeChar.isFakeDeath()) { activeChar.stopFakeDeath(true); break; } if (activeChar.isSitting() || !activeChar.isMoving()) useSit(ch, targ); else { // Sit when arrive using next action, creating next action class. NextAction nextAction = new NextAction(CtrlEvent.EVT_ARRIVED, CtrlIntention.AI_INTENTION_MOVE_TO, new NextActionCallback() { @Override public void doWork() { useSit(ch, targ); } }); // Binding next action to AI. activeChar.getAI().setNextAction(nextAction); } break; case 1: if (activeChar.isRunning()) activeChar.setWalking(); else activeChar.setRunning(); log.trace("new move type: " + (activeChar.isRunning() ? "RUNNING" : "WALKING")); break; case 10: // Private Store - Sell activeChar.tryOpenPrivateSellStore(false); break; case 28: // Private Store - Buy activeChar.tryOpenPrivateBuyStore(); break; case 15: case 21: // Change Movement Mode (pet follow/stop) if (pet != null) { // You can't order anymore your pet to stop if distance is superior to 2000. if (pet.getFollowStatus() && Util.calculateDistance(activeChar, pet, true) > 2000) return; if (!activeChar.isBetrayed()) ((SummonAI) pet.getAI()).notifyFollowStatusChange(); } break; case 16: case 22: // Attack (pet attack) if (target != null && pet != null && pet != target && activeChar != target && !pet.isBetrayed()) { if (pet.isAttackingDisabled()) { if (pet.getAttackEndTime() > GameTimeController.getGameTicks()) pet.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target); else return; } if (pet instanceof L2PetInstance && (pet.getLevel() - activeChar.getLevel() > 20)) { activeChar.sendPacket(SystemMessageId.PET_TOO_HIGH_TO_CONTROL); return; } if (activeChar.isInOlympiadMode() && !activeChar.isOlympiadStart()) { // if L2PcInstance is in Olympia and the match isn't already start, send a Server->Client packet // ActionFailed activeChar.sendPacket(ActionFailed.STATIC_PACKET); return; } if (!activeChar.getAccessLevel().allowPeaceAttack() && L2Character.isInsidePeaceZone(pet, target)) { activeChar.sendPacket(SystemMessageId.TARGET_IN_PEACEZONE); return; } pet.setTarget(target); if (target.isAutoAttackable(activeChar) || _ctrlPressed) { if (target instanceof L2DoorInstance) { if (((L2DoorInstance) target).isAttackable(activeChar) && pet.getNpcId() != L2SiegeSummonInstance.SWOOP_CANNON_ID) pet.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target); } // siege golem AI doesn't support attacking other than doors at the moment else if (pet.getNpcId() != L2SiegeSummonInstance.SIEGE_GOLEM_ID) pet.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target); } else { pet.setFollowStatus(false); pet.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, target); } } break; case 17: case 23: // Stop (pet - cancel action) if (pet != null && !pet.isMovementDisabled() && !pet.isBetrayed()) pet.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE, null); break; case 19: // Returns pet to control item if (pet != null && pet instanceof L2PetInstance) { if (pet.isDead()) activeChar.sendPacket(SystemMessageId.DEAD_PET_CANNOT_BE_RETURNED); else if (pet.isBetrayed() || pet.isMovementDisabled()) activeChar.sendPacket(SystemMessageId.PET_REFUSING_ORDER); else if (pet.isAttackingNow() || pet.isInCombat()) activeChar.sendPacket(SystemMessageId.PET_CANNOT_SENT_BACK_DURING_BATTLE); else { // if the pet is hungry, you can't unsummon it if (((L2PetInstance) pet).isHungry()) activeChar.sendPacket(SystemMessageId.YOU_CANNOT_RESTORE_HUNGRY_PETS); else pet.unSummon(activeChar); } } break; case 38: // pet mount/dismount activeChar.mountPlayer(pet); break; case 32: // Wild Hog Cannon - Mode Change useSkill(4230); break; case 36: // Soulless - Toxic Smoke useSkill(4259); break; case 37: // Dwarven Manufacture activeChar.tryOpenWorkshop(true); break; case 39: // Soulless - Parasite Burst useSkill(4138); break; case 41: // Wild Hog Cannon - Attack useSkill(4230); break; case 42: // Kai the Cat - Self Damage Shield useSkill(4378, activeChar); break; case 43: // Unicorn Merrow - Hydro Screw useSkill(4137); break; case 44: // Big Boom - Boom Attack useSkill(4139); break; case 45: // Unicorn Boxer - Master Recharge useSkill(4025, activeChar); break; case 46: // Mew the Cat - Mega Storm Strike useSkill(4261); break; case 47: // Silhouette - Steal Blood useSkill(4260); break; case 48: // Mechanic Golem - Mech. Cannon useSkill(4068); break; case 51: // General Manufacture activeChar.tryOpenWorkshop(false); break; case 52: // Unsummon a servitor if (pet != null && pet instanceof L2SummonInstance) { if (pet.isDead()) activeChar.sendPacket(SystemMessageId.DEAD_PET_CANNOT_BE_RETURNED); else if (pet.isBetrayed() || pet.isMovementDisabled()) activeChar.sendPacket(SystemMessageId.PET_REFUSING_ORDER); else if (pet.isAttackingNow() || pet.isInCombat()) activeChar.sendPacket(SystemMessageId.PET_CANNOT_SENT_BACK_DURING_BATTLE); else pet.unSummon(activeChar); } break; case 53: // move to target case 54: // move to target hatch/strider if (target != null && pet != null && pet != target && !pet.isMovementDisabled() && !pet.isBetrayed()) { pet.setFollowStatus(false); pet.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(target.getX(), target.getY(), target.getZ(), 0)); } break; case 61: // Private Store Package Sell activeChar.tryOpenPrivateSellStore(true); case 1000: // Siege Golem - Siege Hammer if (target instanceof L2DoorInstance) useSkill(4079); break; case 1001: // Sin Eater - Ultimate Bombastic Buster // useSkill(); break; case 1003: // Wind Hatchling/Strider - Wild Stun useSkill(4710); break; case 1004: // Wind Hatchling/Strider - Wild Defense useSkill(4711, activeChar); break; case 1005: // Star Hatchling/Strider - Bright Burst useSkill(4712); break; case 1006: // Star Hatchling/Strider - Bright Heal useSkill(4713, activeChar); break; case 1007: // Cat Queen - Blessing of Queen useSkill(4699, activeChar); break; case 1008: // Cat Queen - Gift of Queen useSkill(4700, activeChar); break; case 1009: // Cat Queen - Cure of Queen useSkill(4701); break; case 1010: // Unicorn Seraphim - Blessing of Seraphim useSkill(4702, activeChar); break; case 1011: // Unicorn Seraphim - Gift of Seraphim useSkill(4703, activeChar); break; case 1012: // Unicorn Seraphim - Cure of Seraphim useSkill(4704); break; case 1013: // Nightshade - Curse of Shade useSkill(4705); break; case 1014: // Nightshade - Mass Curse of Shade useSkill(4706, activeChar); break; case 1015: // Nightshade - Shade Sacrifice useSkill(4707); break; case 1016: // Cursed Man - Cursed Blow useSkill(4709); break; case 1017: // Cursed Man - Cursed Strike/Stun useSkill(4708); break; case 1031: // Feline King - Slash useSkill(5135); break; case 1032: // Feline King - Spinning Slash useSkill(5136); break; case 1033: // Feline King - Grip of the Cat useSkill(5137); break; case 1034: // Magnus the Unicorn - Whiplash useSkill(5138); break; case 1035: // Magnus the Unicorn - Tridal Wave useSkill(5139); break; case 1036: // Spectral Lord - Corpse Kaboom useSkill(5142); break; case 1037: // Spectral Lord - Dicing Death useSkill(5141); break; case 1038: // Spectral Lord - Force Curse useSkill(5140); break; case 1039: // Swoop Cannon - Cannon Fodder if (!(target instanceof L2DoorInstance)) useSkill(5110); break; case 1040: // Swoop Cannon - Big Bang if (!(target instanceof L2DoorInstance)) useSkill(5111); break; default: log.warn(activeChar.getName() + ": unhandled action type " + _actionId); } } public static boolean useSit(L2PcInstance activeChar, L2Object target) { if (activeChar.getMountType() != 0) return false; if (target != null && !activeChar.isSitting() && target instanceof L2StaticObjectInstance && ((L2StaticObjectInstance) target).getType() == 1 && CastleManager.getInstance().getCastle(target) != null && activeChar.isInsideRadius(target, L2StaticObjectInstance.INTERACTION_DISTANCE, false, false)) { final ChairSit cs = new ChairSit(activeChar, ((L2StaticObjectInstance) target).getStaticObjectId()); activeChar.sendPacket(cs); activeChar.sitDown(); activeChar.broadcastPacket(cs); return false; } if (activeChar.isSitting()) activeChar.standUp(); else activeChar.sitDown(); log.trace("new wait type: " + (activeChar.isSitting() ? "SITTING" : "STANDING")); return true; } /* * Cast a skill for active pet/servitor. Target is specified as a parameter but can be overwrited or ignored depending on skill type. */ private void useSkill(int skillId, L2Object target) { final L2PcInstance activeChar = getClient().getActiveChar(); if (activeChar == null || activeChar.getPrivateStoreType() != 0) return; final L2Summon activeSummon = activeChar.getPet(); if (activeSummon != null && !activeSummon.isBetrayed()) { if (activeSummon instanceof L2PetInstance) { if (activeSummon.getLevel() - activeChar.getLevel() > 20) { activeChar.sendPacket(SystemMessageId.PET_TOO_HIGH_TO_CONTROL); return; } } TIntObjectHashMap<L2Skill> _skills = activeSummon.getTemplate().getSkills(); if (_skills == null || _skills.isEmpty()) return; L2Skill skill = _skills.get(skillId); if (skill == null) { log.warn(activeSummon.getName() + " does not have the skill id " + skillId + " assigned."); return; } if (skill.isOffensive() && activeChar == target) return; activeSummon.setTarget(target); activeSummon.useMagic(skill, _ctrlPressed, _shiftPressed); } } /* * Cast a skill for active pet/servitor. Target is retrieved from owner' target, then validated by overloaded method useSkill(int, L2Object). */ private void useSkill(int skillId) { final L2PcInstance activeChar = getClient().getActiveChar(); if (activeChar == null) return; useSkill(skillId, activeChar.getTarget()); } }