/*
* 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.List;
import javastory.channel.ChannelCharacter;
import javastory.channel.ChannelClient;
import javastory.channel.life.MobSkill;
import javastory.channel.life.Monster;
import javastory.channel.maps.GameMap;
import javastory.channel.movement.LifeMovementFragment;
import javastory.channel.packet.MobPacket;
import javastory.game.SkillLevelEntry;
import javastory.game.data.MobSkillFactory;
import javastory.io.PacketFormatException;
import javastory.io.PacketReader;
import javastory.tools.Randomizer;
public class MobHandler {
public static void handleMoveMonster(final PacketReader reader, final ChannelClient c, final ChannelCharacter chr) throws PacketFormatException {
final Monster monster = chr.getMap().getMonsterByOid(reader.readInt());
if (monster == null) { // movin something which is not a monster
return;
}
final short moveid = reader.readShort();
final boolean useSkill = reader.readByte() > 0;
final byte skill = reader.readByte();
final int skill1 = reader.readByte() & 0xFF; // unsigned?
final int skill2 = reader.readByte();
final int skill3 = reader.readByte();
final int skill4 = reader.readByte();
int realskill = 0;
int level = 0;
if (useSkill) {// && (skill == -1 || skill == 0)) {
final byte size = monster.getNoSkills();
boolean used = false;
if (size > 0) {
final SkillLevelEntry skillToUse = monster.getSkills().get((byte) Randomizer.nextInt(size));
realskill = skillToUse.skill;
level = skillToUse.level;
// Skill ID and Level
final MobSkill mobSkill = MobSkillFactory.getMobSkill(realskill, level);
if (!mobSkill.checkCurrentBuff(chr, monster)) {
final long now = System.currentTimeMillis();
final long ls = monster.getLastSkillUsed(realskill);
if (ls == 0 || now - ls > mobSkill.getCoolTime()) {
monster.setLastSkillUsed(realskill, now, mobSkill.getCoolTime());
final int reqHp = (int) ((float) monster.getHp() / monster.getMobMaxHp() * 100);
// In case this monster have 2.1b and above HP
if (reqHp <= mobSkill.getHP()) {
used = true;
mobSkill.applyEffect(chr, monster, true);
}
}
}
}
if (!used) {
realskill = 0;
level = 0;
}
}
reader.skip(33);
final Point startPos = monster.getPosition();
final List<LifeMovementFragment> res = MovementParse.parseMovement(reader);
c.write(MobPacket.moveMonsterResponse(monster.getObjectId(), moveid, monster.getMp(), monster.isControllerHasAggro(), realskill, level));
if (res != null) {
if (reader.remaining() != 9 && reader.remaining() != 17) {
// 9.. 0 -> endPos? -> endPos again? -> 0 -> 0
System.out.println("reader.available != 17 (movement parsing error)");
c.disconnect(true);
return;
}
/*
* reader.skip(1); final short fromx = reader.readShort(); final
* short fromy = reader.readShort(); final short tox =
* reader.readShort(); final short toy = reader.readShort();
* System.out
* .println("x1 : "+fromx+", y2 : "+fromy+" x2 : "+tox+", y2 : " +
* toy);
* System.out.println(map.getFootholds().checkRelevantFH(fromx,
* fromy, tox, toy));
*/
final GameMap map = c.getPlayer().getMap();
MovementParse.updatePosition(res, monster, -1);
map.moveMonster(monster, monster.getPosition());
map.broadcastMessage(chr, MobPacket.moveMonster(useSkill, skill, skill1, skill2, skill3, skill4, monster.getObjectId(), startPos, res), monster
.getPosition());
chr.getCheatTracker().checkMoveMonster(monster.getPosition());
}
}
public static void handleFriendlyDamage(final PacketReader reader, final ChannelCharacter chr) throws PacketFormatException {
final GameMap map = chr.getMap();
final Monster mobfrom = map.getMonsterByOid(reader.readInt());
reader.skip(4); // Player ID
final Monster mobto = map.getMonsterByOid(reader.readInt());
if (mobfrom != null && mobto != null && mobto.getStats().isFriendly()) {
final int damage = mobto.getStats().getLevel() * Randomizer.nextInt(99) / 2; // Temp
// for
// now
// until
// I
// figure
// out
// something
// more
// effective
mobto.damage(chr, damage, true);
}
}
public static void handleMonsterBomb(final int oid, final ChannelCharacter chr) {
final Monster monster = chr.getMap().getMonsterByOid(oid);
if (monster == null || !chr.isAlive() || chr.isHidden()) {
return;
}
final byte selfd = monster.getStats().getSelfD();
if (selfd != -1) {
chr.getMap().killMonster(monster, chr, false, false, selfd);
}
}
public static void handleAutoAggro(final int monsteroid, final ChannelCharacter chr) {
final Monster monster = chr.getMap().getMonsterByOid(monsteroid);
if (monster != null && chr.getPosition().distance(monster.getPosition()) < 200000) {
if (monster.getController() != null) {
if (chr.getMap().getCharacterById_InMap(monster.getController().getId()) == null) {
monster.switchController(chr, true);
} else {
monster.switchController(monster.getController(), true);
}
} else {
monster.switchController(chr, true);
}
}
}
public static void handleHypnotizeDamage(final PacketReader reader, final ChannelCharacter chr) throws PacketFormatException {
final Monster mob_from = chr.getMap().getMonsterByOid(reader.readInt()); // From
reader.skip(4); // Player ID
final int to = reader.readInt(); // mobto
reader.skip(1); // Same as player damage, -1 = bump, integer = skill ID
final int damage = reader.readInt();
// reader.skip(1); // Facing direction
// reader.skip(4); // Some type of pos, damage display, I think
final Monster mob_to = chr.getMap().getMonsterByOid(to);
if (mob_from != null && mob_to != null) {
if (damage > 30000) {
return;
}
mob_to.damage(chr, damage, true);
// TODO : Get the real broadcast damage packet
chr.getMap().broadcastMessage(chr, MobPacket.damageMonster(to, damage), false);
}
}
}