/*
* This file is part of the OdinMS Maple Story Server Copyright (C) 2008 ~ 2010
* Patrick Huy <patrick.huy@frz.cc> Matthias Butz <matze@odinms.de> Jan
* Christian Meyer <vimes@odinms.de>
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation. You may not use, modify or distribute this
* program under any other version of the GNU Affero General Public License.
*
* 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 Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package javastory.channel.handling;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javastory.channel.ChannelCharacter;
import javastory.channel.ChannelClient;
import javastory.channel.anticheat.CheatingOffense;
import javastory.channel.client.BuffStat;
import javastory.channel.client.ISkill;
import javastory.channel.client.MonsterStatusEffect;
import javastory.channel.life.Monster;
import javastory.channel.life.SummonAttackEntry;
import javastory.channel.maps.GameMap;
import javastory.channel.maps.GameMapObject;
import javastory.channel.maps.GameMapObjectType;
import javastory.channel.maps.Summon;
import javastory.channel.maps.SummonMovementType;
import javastory.channel.movement.LifeMovementFragment;
import javastory.channel.server.StatEffect;
import javastory.game.data.SkillInfoProvider;
import javastory.game.data.SummonSkillEntry;
import javastory.io.PacketFormatException;
import javastory.io.PacketReader;
import javastory.tools.packets.ChannelPackets;
public final class SummonHandler {
private SummonHandler() {
}
public static void handleMoveDragon(final PacketReader reader, final ChannelCharacter chr) throws PacketFormatException {
reader.skip(8); //POS
final List<LifeMovementFragment> res = MovementParse.parseMovement(reader);
if (chr.getDragon() != null) {
final Point pos = chr.getDragon().getPosition();
MovementParse.updatePosition(res, chr.getDragon(), 0);
if (!chr.isHidden()) {
chr.getMap().broadcastMessage(chr, ChannelPackets.moveDragon(chr.getDragon(), pos, res), chr.getPosition());
}
}
}
public static void handleSummonMove(final PacketReader reader, final ChannelCharacter chr) throws PacketFormatException {
final int oid = reader.readInt();
reader.skip(8);
final List<LifeMovementFragment> res = MovementParse.parseMovement(reader);
for (final Summon sum : chr.getSummons().values()) {
if (sum.getObjectId() == oid && sum.getMovementType() != SummonMovementType.STATIONARY) {
final Point startPos = sum.getPosition();
MovementParse.updatePosition(res, sum, 0);
chr.getMap().broadcastMessage(chr, ChannelPackets.moveSummon(chr.getId(), oid, startPos, res), sum.getPosition());
break;
}
}
}
public static void handleSummonDamage(final PacketReader reader, final ChannelCharacter chr) throws PacketFormatException {
final int unkByte = reader.readByte();
final int damage = reader.readInt();
final int monsterIdFrom = reader.readInt();
// reader.readByte(); // stance
final Iterator<Summon> iter = chr.getSummons().values().iterator();
Summon summon;
while (iter.hasNext()) {
summon = iter.next();
if (summon.isPuppet() && summon.getOwnerId() == chr.getId()) { //We can only have one puppet(AFAIK O.O) so this check is safe.
summon.addHP((short) -damage);
if (summon.getHP() <= 0) {
chr.cancelEffectFromBuffStat(BuffStat.PUPPET);
}
chr.getMap().broadcastMessage(chr, ChannelPackets.damageSummon(chr.getId(), summon.getSkill(), damage, unkByte, monsterIdFrom),
summon.getPosition());
break;
}
}
}
public static void handleSummonAttack(final PacketReader reader, final ChannelClient c, final ChannelCharacter chr) throws PacketFormatException {
if (!chr.isAlive()) {
chr.getCheatTracker().registerOffense(CheatingOffense.ATTACKING_WHILE_DEAD);
return;
}
final GameMap map = chr.getMap();
final GameMapObject obj = map.getMapObject(reader.readInt());
if (obj == null || !obj.getType().equals(GameMapObjectType.SUMMON)) {
return;
}
final Summon summon = (Summon) obj;
if (summon.getOwnerId() != chr.getId()) {
return;
}
final SummonSkillEntry sse = SkillInfoProvider.getSummonData(summon.getSkill());
if (sse == null) {
return;
}
reader.skip(8);
summon.CheckSummonAttackFrequency(chr, reader.readInt());
reader.skip(8);
final byte animation = reader.readByte();
reader.skip(8);
final byte numAttacked = reader.readByte();
if (numAttacked > sse.MobCount) {
//AutobanManager.getInstance().autoban(c, "Attacking more monster that summon can do (Skillid : "+summon.getSkill()+" Count : " + numAttacked + ", allowed : " + sse.mobCount + ")");
return;
}
reader.skip(8);
final List<SummonAttackEntry> allDamage = new ArrayList<SummonAttackEntry>();
chr.getCheatTracker().checkSummonAttack();
for (int i = 0; i < numAttacked; i++) {
final Monster mob = map.getMonsterByOid(reader.readInt());
if (mob == null) {
continue;
}
if (chr.getPosition().distanceSq(mob.getPosition()) > 250000.0) {
chr.getCheatTracker().registerOffense(CheatingOffense.ATTACK_FARAWAY_MONSTER_SUMMON);
}
reader.skip(18); // who knows
final int damage = reader.readInt();
allDamage.add(new SummonAttackEntry(mob, damage));
}
map.broadcastMessage(chr, ChannelPackets.summonAttack(summon.getOwnerId(), summon.getSkill(), animation, allDamage, chr.getLevel()), summon
.getPosition());
final ISkill summonSkill = SkillInfoProvider.getSkill(summon.getSkill());
final StatEffect summonEffect = summonSkill.getEffect(summon.getSkillLevel());
for (final SummonAttackEntry attackEntry : allDamage) {
final int toDamage = attackEntry.getDamage();
final Monster mob = attackEntry.getMonster();
if (toDamage > 0 && summonEffect.getMonsterStati().size() > 0) {
if (summonEffect.makeChanceResult()) {
mob.applyStatus(chr, new MonsterStatusEffect(summonEffect.getMonsterStati(), summonSkill, null, false), summonEffect.isPoison(), 4000,
false);
}
}
if (chr.isGM() || toDamage < 60000) {
mob.damage(chr, toDamage, true);
chr.checkMonsterAggro(mob);
} else {
//AutobanManager.getInstance().autoban(c, "High Summon Damage (" + toDamage + " to " + attackEntry.getMonster().getId() + ")");
// TODO : Check player's stat for damage checking.
}
}
}
}