MapleMonster.java
资源名称:src.rar [点击查看]
上传用户:gwt600
上传日期:2021-06-03
资源大小:704k
文件大小:42k
源码类别:
游戏
开发平台:
Java
- /*
- This file is part of the OdinMS Maple Story Server
- Copyright (C) 2008 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 net.sf.odinms.server.life;
- import java.lang.ref.WeakReference;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.LinkedHashMap;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Random;
- import java.util.Map.Entry;
- import java.util.concurrent.ScheduledFuture;
- import net.sf.odinms.client.MapleBuffStat;
- import net.sf.odinms.client.MapleCharacter;
- import net.sf.odinms.client.MapleClient;
- import net.sf.odinms.client.MapleInventory;
- import net.sf.odinms.client.MapleInventoryType;
- import net.sf.odinms.client.MapleJob;
- import net.sf.odinms.client.SkillFactory;
- import net.sf.odinms.client.status.MonsterStatus;
- import net.sf.odinms.client.status.MonsterStatusEffect;
- import net.sf.odinms.net.MaplePacket;
- import net.sf.odinms.net.channel.ChannelServer;
- import net.sf.odinms.net.world.MapleParty;
- import net.sf.odinms.net.world.MaplePartyCharacter;
- import net.sf.odinms.scripting.event.EventInstanceManager;
- import net.sf.odinms.server.TimerManager;
- import net.sf.odinms.server.life.MapleMonsterInformationProvider.DropEntry;
- import net.sf.odinms.server.maps.MapleMap;
- import net.sf.odinms.server.maps.MapleMapObject;
- import net.sf.odinms.server.maps.MapleMapObjectType;
- import net.sf.odinms.tools.ArrayMap;
- import net.sf.odinms.tools.MaplePacketCreator;
- import net.sf.odinms.tools.Pair;
- public class MapleMonster extends AbstractLoadedMapleLife {
- private MapleMonsterStats stats;
- private MapleMonsterStats overrideStats;
- private int hp;
- private int team = -1;
- private int mp;
- private WeakReference<MapleCharacter> controller = new WeakReference<MapleCharacter>(null);
- private boolean controllerHasAggro, controllerKnowsAboutAggro;
- private Collection<AttackerEntry> attackers = new LinkedList<AttackerEntry>();
- private EventInstanceManager eventInstance = null;
- private Collection<MonsterListener> listeners = new LinkedList<MonsterListener>();
- private MapleCharacter highestDamageChar;
- private Map<MonsterStatus, MonsterStatusEffect> stati = new LinkedHashMap<MonsterStatus, MonsterStatusEffect>();
- private List<MonsterStatusEffect> activeEffects = new ArrayList<MonsterStatusEffect>();
- private MapleMap map;
- private int VenomMultiplier = 0;
- private boolean fake = false;
- private boolean dropsDisabled = false;
- private List<Pair<Integer, Integer>> usedSkills = new ArrayList<Pair<Integer, Integer>>();
- private Map<Pair<Integer, Integer>, Integer> skillsUsed = new HashMap<Pair<Integer, Integer>, Integer>();
- private List<MonsterStatus> monsterBuffs = new ArrayList<MonsterStatus>();
- public MapleMonster(int id, MapleMonsterStats stats) {
- super(id);
- initWithStats(stats);
- }
- public MapleMonster(MapleMonster monster) {
- super(monster);
- initWithStats(monster.stats);
- }
- private void initWithStats(MapleMonsterStats stats) {
- setStance(5);
- this.stats = stats;
- hp = stats.getHp();
- mp = stats.getMp();
- }
- public void disableDrops() {
- this.dropsDisabled = true;
- }
- public boolean dropsDisabled() {
- return dropsDisabled;
- }
- public void setMap(MapleMap map) {
- this.map = map;
- }
- public int getDrop() {
- MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance();
- int lastAssigned = -1;
- int minChance = 1;
- List<DropEntry> dl = mi.retrieveDropChances(getId());
- for (DropEntry d : dl) {
- if (d.chance > minChance) {
- minChance = d.chance;
- }
- }
- for (DropEntry d : dl) {
- d.assignedRangeStart = lastAssigned + 1;
- d.assignedRangeLength = (int) Math.ceil(((double) 1 / (double) d.chance) * minChance);
- lastAssigned += d.assignedRangeLength;
- }
- // now produce the randomness o.o
- Random r = new Random();
- int c = r.nextInt(minChance);
- for (DropEntry d : dl) {
- if (c >= d.assignedRangeStart && c < (d.assignedRangeStart + d.assignedRangeLength)) {
- return d.itemId;
- }
- }
- return -1;
- }
- public int getHp() {
- return hp;
- }
- public void setHp(int hp) {
- this.hp = hp;
- }
- public int getMaxHp() {
- if (overrideStats != null) {
- return overrideStats.getHp();
- }
- return stats.getHp();
- }
- public int getMp() {
- return mp;
- }
- public void setMp(int mp) {
- if (mp < 0) {
- mp = 0;
- }
- this.mp = mp;
- }
- public int getMaxMp() {
- if (overrideStats != null) {
- return overrideStats.getMp();
- }
- return stats.getMp();
- }
- public int getExp() {
- if (overrideStats != null) {
- return overrideStats.getExp();
- }
- return stats.getExp();
- }
- public int getLevel() {
- return stats.getLevel();
- }
- public int getRemoveAfter() {
- return stats.getRemoveAfter();
- }
- public int getVenomMulti() {
- return this.VenomMultiplier;
- }
- public void setVenomMulti(int multiplier) {
- this.VenomMultiplier = multiplier;
- }
- public boolean isBoss() {
- return stats.isBoss() || getId() == 8810018;
- }
- public boolean isFfaLoot() {
- return stats.isFfaLoot();
- }
- public int getAnimationTime(String name) {
- return stats.getAnimationTime(name);
- }
- public List<Integer> getRevives() {
- return stats.getRevives();
- }
- public void setOverrideStats(MapleMonsterStats overrideStats) {
- this.overrideStats = overrideStats;
- }
- public byte getTagColor() {
- return stats.getTagColor();
- }
- public byte getTagBgColor() {
- return stats.getTagBgColor();
- }
- public boolean getUndead() {
- return stats.getUndead();
- }
- /**
- *
- * @param from the player that dealt the damage
- * @param damage
- */
- public void damage(MapleCharacter from, int damage, boolean updateAttackTime) {
- AttackerEntry attacker = null;
- if (from.getParty() != null) {
- attacker = new PartyAttackerEntry(from.getParty().getId(), from.getClient().getChannelServer());
- } else {
- attacker = new SingleAttackerEntry(from, from.getClient().getChannelServer());
- }
- boolean replaced = false;
- for (AttackerEntry aentry : attackers) {
- if (aentry.equals(attacker)) {
- attacker = aentry;
- replaced = true;
- break;
- }
- }
- if (!replaced) {
- attackers.add(attacker);
- }
- int rDamage = Math.max(0, Math.min(damage, this.hp));
- attacker.addDamage(from, rDamage, updateAttackTime);
- this.hp -= rDamage;
- int remhppercentage = (int) Math.ceil((this.hp * 100.0) / getMaxHp());
- if (remhppercentage < 1) {
- remhppercentage = 1;
- }
- long okTime = System.currentTimeMillis() - 4000;
- if (hasBossHPBar()) {
- from.getMap().broadcastMessage(makeBossHPBarPacket(), getPosition());
- } else if (!isBoss()) {
- for (AttackerEntry mattacker : attackers) {
- for (AttackingMapleCharacter cattacker : mattacker.getAttackers()) {
- // current attacker is on the map of the monster
- if (cattacker.getAttacker().getMap() == from.getMap()) {
- if (cattacker.getLastAttackTime() >= okTime) {
- cattacker.getAttacker().getClient().getSession().write(MaplePacketCreator.showMonsterHP(getObjectId(), remhppercentage));
- }
- }
- }
- }
- }
- }
- public int getTeam() {
- return team;
- }
- public void heal(int hp, int mp) {
- // int finalHP = hp / 10000 * ((int) (8000 + 10000 * Math.random()));
- int hp2Heal = getHp() + hp;
- int mp2Heal = getMp() + mp;
- if (hp2Heal >= getMaxHp()) {
- hp2Heal = getMaxHp();
- }
- if (mp2Heal >= getMaxMp()) {
- mp2Heal = getMaxMp();
- }
- setHp(hp2Heal);
- setMp(mp2Heal);
- getMap().broadcastMessage(MaplePacketCreator.healMonster(getObjectId(), hp));
- }
- public boolean isAttackedBy(MapleCharacter chr) {
- for (AttackerEntry aentry : attackers) {
- if (aentry.contains(chr)) {
- return true;
- }
- }
- return false;
- }
- public void giveExpToCharacter(MapleCharacter attacker, int exp, boolean highestDamage, int numExpSharers) {
- MapleInventory r =attacker.getInventory(MapleInventoryType.CASH);
- if (highestDamage) {
- if (eventInstance != null) {
- eventInstance.monsterKilled(attacker, this);
- }
- highestDamageChar = attacker;
- }
- if (attacker.getHp() > 0) {
- int personalExp = exp;
- if (exp > 0) {
- Integer holySymbol = attacker.getBuffedValue(MapleBuffStat.HOLY_SYMBOL);
- if (holySymbol != null) {
- if (numExpSharers == 1) {
- personalExp *= 1.0 + (holySymbol.doubleValue() / 500.0);
- } else {
- personalExp *= 1.0 + (holySymbol.doubleValue() / 100.0);
- }
- }
- }
- while (personalExp > Integer.MAX_VALUE) {
- attacker.gainExp(Integer.MAX_VALUE, true, false, highestDamage);
- personalExp -= Integer.MAX_VALUE;
- }
- /*双倍卡5211018 || 5211003*/
- if (r.findById(5211003) != null) {
- attacker.gainExp(personalExp * 3, true, false, highestDamage);
- if (r.findById(5211017) != null) {
- attacker.gainExp(personalExp * 100, true, false, highestDamage);
- } else if (r.findById(5211018) != null){
- attacker.gainExp(personalExp * 2, true, false, highestDamage);
- } else {
- if (attacker.getClient().getChannel() == ChannelServer.getInstance(attacker.getClient().getChannel()).getblackmsVipCh()) {
- attacker.gainExp((int) (personalExp * ChannelServer.getInstance(attacker.getClient().getChannel()).getVipChExpRate()), true, false, highestDamage);
- } else {
- attacker.gainExp(personalExp, true, false, highestDamage);
- }//这个是给VIP频道怪物经验的
- }
- attacker.mobKilled(this.getId());
- }
- if (exp < 0) {
- personalExp = Integer.MAX_VALUE;
- }
- int exped=personalExp *(attacker.hasexp()+attacker.hasEXPCard());
- if(exped>2100000000){
- exped=2100000000;
- }
- }
- }
- public MapleCharacter killBy(MapleCharacter killer) {
- // broadcastMessage(null, MaplePacketCreator.getPreKillthis(this.getObjectId()));
- // update exp
- long totalBaseExpL = this.getExp() * ChannelServer.getInstance(killer.getClient().getChannel()).getExpRate() * killer.getClient().getPlayer().hasEXPCard();
- int totalBaseExp = (int) (Math.min(Integer.MAX_VALUE, totalBaseExpL));
- AttackerEntry highest = null;
- int highdamage = 0;
- for (AttackerEntry attackEntry : attackers) {
- if (attackEntry.getDamage() > highdamage) {
- highest = attackEntry;
- highdamage = attackEntry.getDamage();
- }
- }
- for (AttackerEntry attackEntry : attackers) {
- int baseExp = (int) Math.ceil(totalBaseExp * ((double) attackEntry.getDamage() / getMaxHp()));
- attackEntry.killedMob(killer.getMap(), baseExp, attackEntry == highest);
- }
- if (this.getController() != null) { // this can/should only happen when a hidden gm attacks the monster
- getController().getClient().getSession().write(MaplePacketCreator.stopControllingMonster(this.getObjectId()));
- getController().stopControllingMonster(this);
- }
- // maybe this isn't the best place to do it, fixme then
- final List<Integer> toSpawn = this.getRevives();
- if (toSpawn != null) {
- final MapleMap reviveMap = killer.getMap();
- TimerManager.getInstance().schedule(new Runnable() {
- public void run() {
- for (Integer mid : toSpawn) {
- MapleMonster mob = MapleLifeFactory.getMonster(mid);
- if (eventInstance != null) {
- eventInstance.registerMonster(mob);
- }
- mob.setPosition(getPosition());
- if (dropsDisabled()) {
- mob.disableDrops();
- }
- reviveMap.spawnRevives(mob);
- }
- }
- //}, this.getAnimationTime("die1") - MapleMonsterInformationProvider.APPROX_FADE_DELAY);
- }, this.getAnimationTime("die1"));
- }
- if (eventInstance != null) {
- eventInstance.unregisterMonster(this);
- }
- for (MonsterListener listener : listeners.toArray(new MonsterListener[listeners.size()])) {
- listener.monsterKilled(this, highestDamageChar);
- }
- MapleCharacter ret = highestDamageChar;
- highestDamageChar = null; // may not keep hard references to chars outside of PlayerStorage or MapleMap
- return ret;
- }
- public boolean isAlive() {
- return this.hp > 0;
- }
- public MapleCharacter getController() {
- return controller.get();
- }
- public void setController(MapleCharacter controller) {
- this.controller = new WeakReference<MapleCharacter>(controller);
- }
- public void switchController(MapleCharacter newController, boolean immediateAggro) {
- MapleCharacter controllers = getController();
- if (controllers == newController) {
- return;
- }
- if (controllers != null) {
- controllers.stopControllingMonster(this);
- controllers.getClient().getSession().write(MaplePacketCreator.stopControllingMonster(getObjectId()));
- }
- newController.controlMonster(this, immediateAggro);
- setController(newController);
- if (immediateAggro) {
- setControllerHasAggro(true);
- }
- setControllerKnowsAboutAggro(false);
- }
- public void addListener(MonsterListener listener) {
- listeners.add(listener);
- }
- public void removeListener(MonsterListener listener) {
- listeners.remove(listener);
- }
- public boolean isControllerHasAggro() {
- if (fake) {
- return false;
- }
- return controllerHasAggro;
- }
- public void setControllerHasAggro(boolean controllerHasAggro) {
- if (fake) {
- return;
- }
- this.controllerHasAggro = controllerHasAggro;
- }
- public boolean isControllerKnowsAboutAggro() {
- if (fake) {
- return false;
- }
- return controllerKnowsAboutAggro;
- }
- public void setControllerKnowsAboutAggro(boolean controllerKnowsAboutAggro) {
- if (fake) {
- return;
- }
- this.controllerKnowsAboutAggro = controllerKnowsAboutAggro;
- }
- public MaplePacket makeBossHPBarPacket() {
- return MaplePacketCreator.showBossHP(getId(), getHp(), getMaxHp(), getTagColor(), getTagBgColor());
- }
- public boolean hasBossHPBar() {
- return (isBoss() && getTagColor() > 0) || isHT();
- }
- private boolean isHT() {
- return this.getId() == 8810018;
- }
- @Override
- public void sendSpawnData(MapleClient client) {
- if (!isAlive() || client.getPlayer().isFake()) {
- return;
- }
- if (isFake()) {
- client.getSession().write(MaplePacketCreator.spawnFakeMonster(this, 0));
- } else {
- client.getSession().write(MaplePacketCreator.spawnMonster(this, false));
- }
- if (stati.size() > 0) {
- for (MonsterStatusEffect mse : activeEffects) {
- MaplePacket packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), mse.getStati(), mse.getSkill().getId(), false, 0);
- client.getSession().write(packet);
- }
- }
- if (hasBossHPBar()) {
- client.getSession().write(makeBossHPBarPacket());
- }
- }
- @Override
- public void sendDestroyData(MapleClient client) {
- client.getSession().write(MaplePacketCreator.killMonster(getObjectId(), false));
- }
- @Override
- public String toString() {
- return getName() + "(" + getId() + ") at " + getPosition().x + "/" + getPosition().y + " with " + getHp() + "/" + getMaxHp() +
- "hp, " + getMp() + "/" + getMaxMp() + " mp (alive: " + isAlive() + " oid: " + getObjectId() + ")";
- }
- @Override
- public MapleMapObjectType getType() {
- return MapleMapObjectType.MONSTER;
- }
- public EventInstanceManager getEventInstance() {
- return eventInstance;
- }
- public void setEventInstance(EventInstanceManager eventInstance) {
- this.eventInstance = eventInstance;
- }
- public boolean isMobile() {
- return stats.isMobile();
- }
- public ElementalEffectiveness getEffectiveness(Element e) {
- if (activeEffects.size() > 0 && stati.get(MonsterStatus.DOOM) != null) {
- return ElementalEffectiveness.NORMAL; // like blue snails
- }
- return stats.getEffectiveness(e);
- }
- public boolean applyStatus(MapleCharacter from, final MonsterStatusEffect status, boolean poison, long duration) {
- return applyStatus(from, status, poison, duration, false);
- }
- public boolean applyStatus(MapleCharacter from, final MonsterStatusEffect status, boolean poison, long duration, boolean venom) {
- switch (stats.getEffectiveness(status.getSkill().getElement())) {
- case IMMUNE:
- case STRONG:
- return false;
- case NORMAL:
- case WEAK:
- break;
- default:
- throw new RuntimeException("Unknown elemental effectiveness: " + stats.getEffectiveness(status.getSkill().getElement()));
- }
- // compos don't have an elemental (they have 2 - so we have to hack here...)
- ElementalEffectiveness effectiveness = null;
- switch (status.getSkill().getId()) {
- case 2111006:
- effectiveness = stats.getEffectiveness(Element.POISON);
- if (effectiveness == ElementalEffectiveness.IMMUNE || effectiveness == ElementalEffectiveness.STRONG) {
- return false;
- }
- break;
- case 2211006:
- effectiveness = stats.getEffectiveness(Element.ICE);
- if (effectiveness == ElementalEffectiveness.IMMUNE || effectiveness == ElementalEffectiveness.STRONG) {
- return false;
- }
- break;
- case 4120005:
- case 4220005:
- effectiveness = stats.getEffectiveness(Element.POISON);
- if (effectiveness == ElementalEffectiveness.WEAK) {
- return false;
- }
- break;
- }
- if (poison && getHp() <= 1) {
- return false;
- }
- if (isBoss() && !(status.getStati().containsKey(MonsterStatus.SPEED))) {
- return false;
- }
- for (MonsterStatus stat : status.getStati().keySet()) {
- MonsterStatusEffect oldEffect = stati.get(stat);
- if (oldEffect != null) {
- oldEffect.removeActiveStatus(stat);
- if (oldEffect.getStati().size() == 0) {
- oldEffect.getCancelTask().cancel(false);
- oldEffect.cancelPoisonSchedule();
- activeEffects.remove(oldEffect);
- }
- }
- }
- TimerManager timerManager = TimerManager.getInstance();
- final Runnable cancelTask = new Runnable() {
- @Override
- public void run() {
- if (isAlive()) {
- MaplePacket packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), status.getStati());
- map.broadcastMessage(packet, getPosition());
- if (getController() != null && !getController().isMapObjectVisible(MapleMonster.this)) {
- getController().getClient().getSession().write(packet);
- }
- }
- activeEffects.remove(status);
- for (MonsterStatus stat : status.getStati().keySet()) {
- stati.remove(stat);
- }
- setVenomMulti(0);
- status.cancelPoisonSchedule();
- }
- };
- if (poison) {
- int poisonLevel = from.getSkillLevel(status.getSkill());
- int poisonDamage = Math.min(Short.MAX_VALUE, (int) (getMaxHp() / (70.0 - poisonLevel) + 0.999));
- status.setValue(MonsterStatus.POISON, Integer.valueOf(poisonDamage));
- status.setPoisonSchedule(timerManager.register(new PoisonTask(poisonDamage, from, status, cancelTask, false), 1000, 1000));
- } else if (venom) {
- if (from.getJob() == MapleJob.NIGHTLORD || from.getJob() == MapleJob.SHADOWER) {
- int poisonLevel = 0;
- int matk = 0;
- if (from.getJob() == MapleJob.NIGHTLORD) {
- poisonLevel = from.getSkillLevel(SkillFactory.getSkill(4120005));
- if (poisonLevel <= 0) {
- return false;
- }
- matk = SkillFactory.getSkill(4120005).getEffect(poisonLevel).getMatk();
- } else if (from.getJob() == MapleJob.SHADOWER) {
- poisonLevel = from.getSkillLevel(SkillFactory.getSkill(4220005));
- if (poisonLevel <= 0) {
- return false;
- }
- matk = SkillFactory.getSkill(4220005).getEffect(poisonLevel).getMatk();
- } else {
- return false;
- }
- Random r = new Random();
- int luk = from.getLuk();
- int maxDmg = (int) Math.ceil(Math.min(Short.MAX_VALUE, 0.2 * luk * matk));
- int minDmg = (int) Math.ceil(Math.min(Short.MAX_VALUE, 0.1 * luk * matk));
- int gap = maxDmg - minDmg;
- if (gap == 0) {
- gap = 1;
- }
- int poisonDamage = 0;
- for (int i = 0; i < getVenomMulti(); i++) {
- poisonDamage = poisonDamage + (r.nextInt(gap) + minDmg);
- }
- poisonDamage = Math.min(Short.MAX_VALUE, poisonDamage);
- status.setValue(MonsterStatus.POISON, Integer.valueOf(poisonDamage));
- status.setPoisonSchedule(timerManager.register(new PoisonTask(poisonDamage, from, status, cancelTask, false), 1000, 1000));
- } else {
- return false;
- }
- } else if (status.getSkill().getId() == 4111003) { // shadow web
- int webDamage = (int) (getMaxHp() / 50.0 + 0.999);
- // actually shadow web works different but similar...
- status.setPoisonSchedule(timerManager.schedule(new PoisonTask(webDamage, from, status, cancelTask, true), 3500));
- }
- for (MonsterStatus stat : status.getStati().keySet()) {
- stati.put(stat, status);
- }
- activeEffects.add(status);
- int animationTime = status.getSkill().getAnimationTime();
- MaplePacket packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), status.getStati(), status.getSkill().getId(), false, 0);
- map.broadcastMessage(packet, getPosition());
- if (getController() != null && !getController().isMapObjectVisible(this)) {
- getController().getClient().getSession().write(packet);
- }
- ScheduledFuture<?> schedule = timerManager.schedule(cancelTask, duration + animationTime);
- status.setCancelTask(schedule);
- return true;
- }
- public void applyMonsterBuff(final MonsterStatus status, final int x, int skillId, long duration, MobSkill skill) {
- TimerManager timerManager = TimerManager.getInstance();
- final Runnable cancelTask = new Runnable() {
- @Override
- public void run() {
- if (isAlive()) {
- MaplePacket packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), Collections.singletonMap(status, Integer.valueOf(x)));
- map.broadcastMessage(packet, getPosition());
- if (getController() != null && !getController().isMapObjectVisible(MapleMonster.this)) {
- getController().getClient().getSession().write(packet);
- }
- removeMonsterBuff(status);
- }
- }
- };
- MaplePacket packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), Collections.singletonMap(status, x), skillId, true, 0, skill);
- map.broadcastMessage(packet, getPosition());
- if (getController() != null && !getController().isMapObjectVisible(this)) {
- getController().getClient().getSession().write(packet);
- }
- timerManager.schedule(cancelTask, duration);
- addMonsterBuff(status);
- }
- public void addMonsterBuff(MonsterStatus status) {
- this.monsterBuffs.add(status);
- }
- public void removeMonsterBuff(MonsterStatus status) {
- this.monsterBuffs.remove(status);
- }
- public boolean isBuffed(MonsterStatus status) {
- return this.monsterBuffs.contains(status);
- }
- public void setFake(boolean fake) {
- this.fake = fake;
- }
- public boolean isFake() {
- return fake;
- }
- public MapleMap getMap() {
- return map;
- }
- public List<Pair<Integer, Integer>> getSkills() {
- return this.stats.getSkills();
- }
- public boolean hasSkill(int skillId, int level) {
- return stats.hasSkill(skillId, level);
- }
- public boolean canUseSkill(MobSkill toUse) {
- if (toUse == null) {
- return false;
- }
- for (Pair<Integer, Integer> skill : usedSkills) {
- if (skill.getLeft() == toUse.getSkillId() && skill.getRight() == toUse.getSkillLevel()) {
- return false;
- }
- }
- if (toUse.getLimit() > 0) {
- if (this.skillsUsed.containsKey(new Pair<Integer, Integer>(toUse.getSkillId(), toUse.getSkillLevel()))) {
- int times = this.skillsUsed.get(new Pair<Integer, Integer>(toUse.getSkillId(), toUse.getSkillLevel()));
- if (times >= toUse.getLimit()) {
- return false;
- }
- }
- }
- if (toUse.getSkillId() == 200) {
- Collection<MapleMapObject> mmo = getMap().getMapObjects();
- int i = 0;
- for (MapleMapObject mo : mmo) {
- if (mo.getType() == MapleMapObjectType.MONSTER) {
- i++;
- }
- }
- if (i > 100) {
- return false;
- }
- }
- return true;
- }
- public void usedSkill(final int skillId, final int level, long cooltime) {
- this.usedSkills.add(new Pair<Integer, Integer>(skillId, level));
- if (this.skillsUsed.containsKey(new Pair<Integer, Integer>(skillId, level))) {
- int times = this.skillsUsed.get(new Pair<Integer, Integer>(skillId, level)) + 1;
- this.skillsUsed.remove(new Pair<Integer, Integer>(skillId, level));
- this.skillsUsed.put(new Pair<Integer, Integer>(skillId, level), times);
- } else {
- this.skillsUsed.put(new Pair<Integer, Integer>(skillId, level), 1);
- }
- final MapleMonster mons = this;
- TimerManager tMan = TimerManager.getInstance();
- tMan.schedule(
- new Runnable() {
- @Override
- public void run() {
- mons.clearSkill(skillId, level);
- }
- }, cooltime);
- }
- public void clearSkill(int skillId, int level) {
- int index = -1;
- for (Pair<Integer, Integer> skill : usedSkills) {
- if (skill.getLeft() == skillId && skill.getRight() == level) {
- index = usedSkills.indexOf(skill);
- break;
- }
- }
- if (index != -1) {
- usedSkills.remove(index);
- }
- }
- public int getNoSkills() {
- return this.stats.getNoSkills();
- }
- public boolean isFirstAttack() {
- return this.stats.isFirstAttack();
- }
- public int getBuffToGive() {
- return this.stats.getBuffToGive();
- }
- public List<MonsterStatus> getMonsterBuffs() {
- return monsterBuffs;
- }
- private final class PoisonTask implements Runnable {
- private final int poisonDamage;
- private final MapleCharacter chr;
- private final MonsterStatusEffect status;
- private final Runnable cancelTask;
- private final boolean shadowWeb;
- private final MapleMap map;
- private PoisonTask(int poisonDamage, MapleCharacter chr, MonsterStatusEffect status, Runnable cancelTask, boolean shadowWeb) {
- this.poisonDamage = poisonDamage;
- this.chr = chr;
- this.status = status;
- this.cancelTask = cancelTask;
- this.shadowWeb = shadowWeb;
- this.map = chr.getMap();
- }
- @Override
- public void run() {
- int damage = poisonDamage;
- if (damage >= hp) {
- damage = hp - 1;
- if (!shadowWeb) {
- cancelTask.run();
- status.getCancelTask().cancel(false);
- }
- }
- if (hp > 1 && damage > 0) {
- damage(chr, damage, false);
- if (shadowWeb) {
- map.broadcastMessage(MaplePacketCreator.damageMonster(getObjectId(), damage), getPosition());
- }
- }
- }
- }
- public String getName() {
- return stats.getName();
- }
- private class AttackingMapleCharacter {
- private MapleCharacter attacker;
- private long lastAttackTime;
- public AttackingMapleCharacter(MapleCharacter attacker, long lastAttackTime) {
- super();
- this.attacker = attacker;
- this.lastAttackTime = lastAttackTime;
- }
- public long getLastAttackTime() {
- return lastAttackTime;
- }
- public void setLastAttackTime(long lastAttackTime) {
- this.lastAttackTime = lastAttackTime;
- }
- public MapleCharacter getAttacker() {
- return attacker;
- }
- }
- private interface AttackerEntry {
- List<AttackingMapleCharacter> getAttackers();
- public void addDamage(MapleCharacter from, int damage, boolean updateAttackTime);
- public int getDamage();
- public boolean contains(MapleCharacter chr);
- public void killedMob(MapleMap map, int baseExp, boolean mostDamage);
- }
- private class SingleAttackerEntry implements AttackerEntry {
- private int damage;
- private int chrid;
- private long lastAttackTime;
- private ChannelServer cserv;
- public SingleAttackerEntry(MapleCharacter from, ChannelServer cserv) {
- this.chrid = from.getId();
- this.cserv = cserv;
- }
- @Override
- public void addDamage(MapleCharacter from, int damage, boolean updateAttackTime) {
- if (chrid == from.getId()) {
- this.damage += damage;
- } else {
- throw new IllegalArgumentException("Not the attacker of this entry");
- }
- if (updateAttackTime) {
- lastAttackTime = System.currentTimeMillis();
- }
- }
- @Override
- public List<AttackingMapleCharacter> getAttackers() {
- MapleCharacter chr = cserv.getPlayerStorage().getCharacterById(chrid);
- if (chr != null) {
- return Collections.singletonList(new AttackingMapleCharacter(chr, lastAttackTime));
- } else {
- return Collections.emptyList();
- }
- }
- @Override
- public boolean contains(MapleCharacter chr) {
- return chrid == chr.getId();
- }
- @Override
- public int getDamage() {
- return damage;
- }
- @Override
- public void killedMob(MapleMap map, int baseExp, boolean mostDamage) {
- MapleCharacter chr = cserv.getPlayerStorage().getCharacterById(chrid);
- if (chr != null && chr.getMap() == map) {
- giveExpToCharacter(chr, baseExp, mostDamage, 1);
- }
- }
- @Override
- public int hashCode() {
- return chrid;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final SingleAttackerEntry other = (SingleAttackerEntry) obj;
- return chrid == other.chrid;
- }
- }
- private static class OnePartyAttacker {
- public MapleParty lastKnownParty;
- public int damage;
- public long lastAttackTime;
- public OnePartyAttacker(MapleParty lastKnownParty, int damage) {
- super();
- this.lastKnownParty = lastKnownParty;
- this.damage = damage;
- this.lastAttackTime = System.currentTimeMillis();
- }
- }
- private class PartyAttackerEntry implements AttackerEntry {
- private int totDamage;
- //private Map<String, Pair<Integer, MapleParty>> attackers;
- private Map<Integer, OnePartyAttacker> attackers;
- private int partyid;
- private ChannelServer cserv;
- public PartyAttackerEntry(int partyid, ChannelServer cserv) {
- this.partyid = partyid;
- this.cserv = cserv;
- attackers = new HashMap<Integer, OnePartyAttacker>(6);
- }
- public List<AttackingMapleCharacter> getAttackers() {
- List<AttackingMapleCharacter> ret = new ArrayList<AttackingMapleCharacter>(attackers.size());
- for (Entry<Integer, OnePartyAttacker> entry : attackers.entrySet()) {
- MapleCharacter chr = cserv.getPlayerStorage().getCharacterById(entry.getKey());
- if (chr != null) {
- ret.add(new AttackingMapleCharacter(chr, entry.getValue().lastAttackTime));
- }
- }
- return ret;
- }
- private Map<MapleCharacter, OnePartyAttacker> resolveAttackers() {
- Map<MapleCharacter, OnePartyAttacker> ret = new HashMap<MapleCharacter, OnePartyAttacker>(attackers.size());
- for (Entry<Integer, OnePartyAttacker> aentry : attackers.entrySet()) {
- MapleCharacter chr = cserv.getPlayerStorage().getCharacterById(aentry.getKey());
- if (chr != null) {
- ret.put(chr, aentry.getValue());
- }
- }
- return ret;
- }
- @Override
- public boolean contains(MapleCharacter chr) {
- return attackers.containsKey(chr.getId());
- }
- @Override
- public int getDamage() {
- return totDamage;
- }
- public void addDamage(MapleCharacter from, int damage, boolean updateAttackTime) {
- OnePartyAttacker oldPartyAttacker = attackers.get(from.getId());
- if (oldPartyAttacker != null) {
- oldPartyAttacker.damage += damage;
- oldPartyAttacker.lastKnownParty = from.getParty();
- if (updateAttackTime) {
- oldPartyAttacker.lastAttackTime = System.currentTimeMillis();
- }
- } else {
- // TODO actually this causes wrong behaviour when the party changes between attacks
- // only the last setup will get exp - but otherwise we'd have to store the full party
- // constellation for every attack/everytime it changes, might be wanted/needed in the
- // future but not now
- OnePartyAttacker onePartyAttacker = new OnePartyAttacker(from.getParty(), damage);
- attackers.put(from.getId(), onePartyAttacker);
- if (!updateAttackTime) {
- onePartyAttacker.lastAttackTime = 0;
- }
- }
- totDamage += damage;
- }
- @Override
- public void killedMob(MapleMap map, int baseExp, boolean mostDamage) {
- Map<MapleCharacter, OnePartyAttacker> attackers_ = resolveAttackers();
- MapleCharacter highest = null;
- int highestDamage = 0;
- Map<MapleCharacter, Integer> expMap = new ArrayMap<MapleCharacter, Integer>(6);
- for (Entry<MapleCharacter, OnePartyAttacker> attacker : attackers_.entrySet()) {
- MapleParty party = attacker.getValue().lastKnownParty;
- double averagePartyLevel = 0;
- List<MapleCharacter> expApplicable = new ArrayList<MapleCharacter>();
- for (MaplePartyCharacter partychar : party.getMembers()) {
- if (attacker.getKey().getLevel() - partychar.getLevel() <= 5 ||
- getLevel() - partychar.getLevel() <= 5) {
- MapleCharacter pchr = cserv.getPlayerStorage().getCharacterByName(partychar.getName());
- if (pchr != null) {
- if (pchr.isAlive() && pchr.getMap() == map) {
- expApplicable.add(pchr);
- averagePartyLevel += pchr.getLevel();
- }
- }
- }
- }
- double expBonus = 1.0;
- if (expApplicable.size() > 1) {
- expBonus = 1.10 + 0.05 * expApplicable.size();
- averagePartyLevel /= expApplicable.size();
- }
- int iDamage = attacker.getValue().damage;
- if (iDamage > highestDamage) {
- highest = attacker.getKey();
- highestDamage = iDamage;
- }
- double innerBaseExp = baseExp * ((double) iDamage / totDamage);
- double expFraction = (innerBaseExp * expBonus) / (expApplicable.size() + 1);
- for (MapleCharacter expReceiver : expApplicable) {
- Integer oexp = expMap.get(expReceiver);
- int iexp;
- if (oexp == null) {
- iexp = 0;
- } else {
- iexp = oexp.intValue();
- }
- double expWeight = (expReceiver == attacker.getKey() ? 2.0 : 1.0);
- double levelMod = expReceiver.getLevel() / averagePartyLevel;
- if (levelMod > 1.0 || this.attackers.containsKey(expReceiver.getId())) {
- levelMod = 1.0;
- }
- iexp += (int) Math.round(expFraction * expWeight * levelMod);
- expMap.put(expReceiver, Integer.valueOf(iexp));
- }
- }
- // FUCK we are done -.-
- for (Entry<MapleCharacter, Integer> expReceiver : expMap.entrySet()) {
- boolean white = mostDamage ? expReceiver.getKey() == highest : false;
- giveExpToCharacter(expReceiver.getKey(), expReceiver.getValue(), white, expMap.size());
- }
- }
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + partyid;
- return result;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final PartyAttackerEntry other = (PartyAttackerEntry) obj;
- if (partyid != other.partyid) {
- return false;
- }
- return true;
- }
- }
- public int getPADamage() {
- return stats.getPADamage();
- }
- }