javastory.channel.life.MobSkill.java Source code

Java tutorial

Introduction

Here is the source code for javastory.channel.life.MobSkill.java

Source

/*
 * 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.life;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javastory.channel.ChannelCharacter;
import javastory.channel.client.Disease;
import javastory.channel.client.MonsterStatus;
import javastory.channel.maps.GameMapObject;
import javastory.channel.maps.GameMapObjectType;
import javastory.channel.maps.Mist;
import javastory.game.BanishInfo;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public class MobSkill {

    private final int skillId, skillLevel;
    private int mpCon;
    private int spawnEffect;
    private int hp;
    private int x;
    private int y;
    private long duration, cooltime;
    private float prop;
    // private short effect_delay;
    private short limit;
    private List<Integer> toSummon = Lists.newArrayList();
    private Point lt, rb;

    public MobSkill(final int skillId, final int level) {
        this.skillId = skillId;
        this.skillLevel = level;
    }

    public void setMpCon(final int mpCon) {
        this.mpCon = mpCon;
    }

    public void addSummons(final List<Integer> toSummon) {
        this.toSummon = toSummon;
    }

    //   public void setEffectDelay(short effect_delay) { 
    //       this.effect_delay =* effect_delay; 
    //   }

    public void setSpawnEffect(final int spawnEffect) {
        this.spawnEffect = spawnEffect;
    }

    public void setHp(final int hp) {
        this.hp = hp;
    }

    public void setX(final int x) {
        this.x = x;
    }

    public void setY(final int y) {
        this.y = y;
    }

    public void setDuration(final long duration) {
        this.duration = duration;
    }

    public void setCoolTime(final long cooltime) {
        this.cooltime = cooltime;
    }

    public void setProp(final float prop) {
        this.prop = prop;
    }

    public void setLtRb(final Point lt, final Point rb) {
        this.lt = lt;
        this.rb = rb;
    }

    public void setLimit(final short limit) {
        this.limit = limit;
    }

    public boolean checkCurrentBuff(final ChannelCharacter player, final Monster monster) {
        boolean stop = false;
        switch (this.skillId) {
        case 100:
        case 110:
            stop = monster.isBuffed(MonsterStatus.WEAPON_ATTACK_UP);
            break;
        case 101:
        case 111:
            stop = monster.isBuffed(MonsterStatus.MAGIC_ATTACK_UP);
            break;
        case 102:
        case 112:
            stop = monster.isBuffed(MonsterStatus.WEAPON_DEFENSE_UP);
            break;
        case 103:
        case 113:
            stop = monster.isBuffed(MonsterStatus.MAGIC_DEFENSE_UP);
            break;
        case 140:
        case 141:
        case 143:
        case 144:
        case 145:
            stop = monster.isBuffed(MonsterStatus.MAGIC_IMMUNITY)
                    || monster.isBuffed(MonsterStatus.WEAPON_IMMUNITY);
            break;
        case 200:
            // int count = 0;
            // for (MapleMapObject ob_mob : player.getMap().getAllMonster()) {
            // if (((MapleMonster) ob_mob).getId() == 0) {
            // count++;
            // }
            // }
            stop = player.getMap().getAllMonster().size() >= this.limit;
            break;
        }
        return stop;
    }

    public void applyEffect(final ChannelCharacter player, final Monster monster, final boolean skill) {
        Disease disease = null;
        final Map<MonsterStatus, Integer> stats = Maps.newEnumMap(MonsterStatus.class);
        final List<Integer> reflection = Lists.newLinkedList();

        switch (this.skillId) {
        case 100:
        case 110:
            stats.put(MonsterStatus.WEAPON_ATTACK_UP, Integer.valueOf(this.x));
            break;
        case 101:
        case 111:
            stats.put(MonsterStatus.MAGIC_ATTACK_UP, Integer.valueOf(this.x));
            break;
        case 102:
        case 112:
            stats.put(MonsterStatus.WEAPON_DEFENSE_UP, Integer.valueOf(this.x));
            break;
        case 103:
        case 113:
            stats.put(MonsterStatus.MAGIC_DEFENSE_UP, Integer.valueOf(this.x));
            break;
        case 114:
            if (this.lt != null && this.rb != null && skill) {
                final List<GameMapObject> objects = this.getObjectsInRange(monster, GameMapObjectType.MONSTER);
                final int hp = this.getX() / 1000 * (int) (950 + 1050 * Math.random());
                for (final GameMapObject mons : objects) {
                    ((Monster) mons).heal(hp, this.getY(), true);
                }
            } else {
                monster.heal(this.getX(), this.getY(), true);
            }
            break;
        case 120:
            disease = Disease.SEAL;
            break;
        case 121:
            disease = Disease.DARKNESS;
            break;
        case 122:
            disease = Disease.WEAKEN;
            break;
        case 123:
            disease = Disease.STUN;
            break;
        case 124:
            disease = Disease.CURSE;
            break;
        case 125:
            disease = Disease.POISON;
            break;
        case 126: // Slow
            disease = Disease.SLOW;
            break;
        case 127:
            if (this.lt != null && this.rb != null && skill) {
                for (final ChannelCharacter character : this.getPlayersInRange(monster, player)) {
                    character.dispel();
                }
            } else {
                player.dispel();
            }
            break;
        case 128: // Seduce
            disease = Disease.SEDUCE;
            break;
        case 129: // Banish
            final BanishInfo info = monster.getStats().getBanishInfo();
            if (this.lt != null && this.rb != null && skill) {
                for (final ChannelCharacter chr : this.getPlayersInRange(monster, player)) {
                    chr.changeMapBanish(info.Map, info.Portal, info.Message);
                }
            } else {
                player.changeMapBanish(info.Map, info.Portal, info.Message);
            }
            break;
        case 131: // Mist
            monster.getMap().spawnMist(
                    new Mist(this.calculateBoundingBox(monster.getPosition(), true), monster, this), this.x * 10,
                    false, false);
            break;
        case 132:
            disease = Disease.REVERSE_DIRECTION;
            break;
        case 133:
            disease = Disease.ZOMBIFY;
            break;
        case 140:
            if (this.makeChanceResult()) {
                stats.put(MonsterStatus.WEAPON_IMMUNITY, Integer.valueOf(this.x));
            }
            break;
        case 141:
            if (this.makeChanceResult()) {
                stats.put(MonsterStatus.MAGIC_IMMUNITY, Integer.valueOf(this.x));
            }
            break;
        case 143: // Weapon Reflect
            stats.put(MonsterStatus.WEAPON_DAMAGE_REFLECT, Integer.valueOf(this.x));
            stats.put(MonsterStatus.WEAPON_IMMUNITY, Integer.valueOf(this.x));
            reflection.add(this.x);
            break;
        case 144: // Magic Reflect
            stats.put(MonsterStatus.MAGIC_DAMAGE_REFLECT, Integer.valueOf(this.x));
            stats.put(MonsterStatus.MAGIC_IMMUNITY, Integer.valueOf(this.x));
            reflection.add(this.x);
            break;
        case 145: // Weapon / Magic reflect
            stats.put(MonsterStatus.WEAPON_DAMAGE_REFLECT, Integer.valueOf(this.x));
            stats.put(MonsterStatus.WEAPON_IMMUNITY, Integer.valueOf(this.x));
            stats.put(MonsterStatus.MAGIC_DAMAGE_REFLECT, Integer.valueOf(this.x));
            stats.put(MonsterStatus.MAGIC_IMMUNITY, Integer.valueOf(this.x));
            reflection.add(this.x);
            reflection.add(this.x);
            break;
        case 200:
            for (final Integer mobId : this.getSummons()) {
                final Monster toSpawn = LifeFactory.getMonster(mobId);
                toSpawn.setPosition(monster.getPosition());
                int ypos = (int) monster.getPosition().getY(), xpos = (int) monster.getPosition().getX();

                switch (mobId) {
                case 8500003: // Pap bomb high
                    toSpawn.setFoothold((int) Math.ceil(Math.random() * 19.0));
                    ypos = -590;
                    break;
                case 8500004: // Pap bomb
                    // Spawn between -500 and 500 from the monsters X position
                    xpos = (int) (monster.getPosition().getX() + Math.ceil(Math.random() * 1000.0) - 500);
                    ypos = (int) monster.getPosition().getY();
                    break;
                case 8510100: // Pianus bomb
                    if (Math.ceil(Math.random() * 5) == 1) {
                        ypos = 78;
                        xpos = (int) (0 + Math.ceil(Math.random() * 5))
                                + (Math.ceil(Math.random() * 2) == 1 ? 180 : 0);
                    } else {
                        xpos = (int) (monster.getPosition().getX() + Math.ceil(Math.random() * 1000.0) - 500);
                    }
                    break;
                }
                // Get spawn coordinates (This fixes monster lock)
                // TODO get map left and right wall.
                switch (monster.getMap().getId()) {
                case 220080001: // Pap map
                    if (xpos < -890) {
                        xpos = (int) (-890 + Math.ceil(Math.random() * 150));
                    } else if (xpos > 230) {
                        xpos = (int) (230 - Math.ceil(Math.random() * 150));
                    }
                    break;
                case 230040420: // Pianus map
                    if (xpos < -239) {
                        xpos = (int) (-239 + Math.ceil(Math.random() * 150));
                    } else if (xpos > 371) {
                        xpos = (int) (371 - Math.ceil(Math.random() * 150));
                    }
                    break;
                }
                monster.getMap().spawnMonsterWithEffect(toSpawn, this.getSpawnEffect(),
                        monster.getMap().calcPointBelow(new Point(xpos, ypos - 1)));
            }
            break;
        }

        if (stats.size() > 0) {
            if (this.lt != null && this.rb != null && skill) {
                for (final GameMapObject mons : this.getObjectsInRange(monster, GameMapObjectType.MONSTER)) {
                    ((Monster) mons).applyMonsterBuff(stats, this.getX(), this.getSkillId(), this.getDuration(),
                            this, reflection);
                }
            } else {
                monster.applyMonsterBuff(stats, this.getX(), this.getSkillId(), this.getDuration(), this,
                        reflection);
            }
        }
        if (disease != null) {
            if (this.lt != null && this.rb != null && skill) {
                for (final ChannelCharacter chr : this.getPlayersInRange(monster, player)) {
                    chr.giveDebuff(disease, this);
                }
            } else {
                player.giveDebuff(disease, this);
            }
        }
        monster.setMp(monster.getMp() - this.getMpCon());
    }

    public int getSkillId() {
        return this.skillId;
    }

    public int getSkillLevel() {
        return this.skillLevel;
    }

    public int getMpCon() {
        return this.mpCon;
    }

    public List<Integer> getSummons() {
        return Collections.unmodifiableList(this.toSummon);
    }

    /*
     * public short getEffectDelay() { return effect_delay; }
     */
    public int getSpawnEffect() {
        return this.spawnEffect;
    }

    public int getHP() {
        return this.hp;
    }

    public int getX() {
        return this.x;
    }

    public int getY() {
        return this.y;
    }

    public long getDuration() {
        return this.duration;
    }

    public long getCoolTime() {
        return this.cooltime;
    }

    public Point getLt() {
        return this.lt;
    }

    public Point getRb() {
        return this.rb;
    }

    public int getLimit() {
        return this.limit;
    }

    public boolean makeChanceResult() {
        return this.prop == 1.0 || Math.random() < this.prop;
    }

    private Rectangle calculateBoundingBox(final Point posFrom, final boolean facingLeft) {
        Point mylt, myrb;
        if (facingLeft) {
            mylt = new Point(this.lt.x + posFrom.x, this.lt.y + posFrom.y);
            myrb = new Point(this.rb.x + posFrom.x, this.rb.y + posFrom.y);
        } else {
            myrb = new Point(this.lt.x * -1 + posFrom.x, this.rb.y + posFrom.y);
            mylt = new Point(this.rb.x * -1 + posFrom.x, this.lt.y + posFrom.y);
        }
        final Rectangle bounds = new Rectangle(mylt.x, mylt.y, myrb.x - mylt.x, myrb.y - mylt.y);
        return bounds;
    }

    private List<ChannelCharacter> getPlayersInRange(final Monster monster, final ChannelCharacter player) {
        final Rectangle bounds = this.calculateBoundingBox(monster.getPosition(), monster.isFacingLeft());
        final List<ChannelCharacter> players = Lists.newArrayList();
        players.add(player);
        return monster.getMap().getPlayersInRect(bounds, players);
    }

    private List<GameMapObject> getObjectsInRange(final Monster monster, final GameMapObjectType objectType) {
        final Rectangle bounds = this.calculateBoundingBox(monster.getPosition(), monster.isFacingLeft());
        final List<GameMapObjectType> objectTypes = Lists.newArrayList();
        objectTypes.add(objectType);
        return monster.getMap().getMapObjectsInRect(bounds, objectTypes);
    }
}