⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 maplemonster.java.svn-base

📁 冒险岛私服Java版服务端(Odinms)源代码。学习JAVA开发的朋友
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
/*
	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.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.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.MapleMapObjectType;
import net.sf.odinms.tools.ArrayMap;
import net.sf.odinms.tools.MaplePacketCreator;

public class MapleMonster extends AbstractLoadedMapleLife {
	private MapleMonsterStats stats;
	private MapleMonsterStats overrideStats;
	private int hp;
	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 static Logger log = LoggerFactory.getLogger(MapleMonster.class);

	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 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) (((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) {
		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 boolean isBoss() {
		return stats.isBoss();
	}
	
	public int getAnimationTime(String name) {
		return stats.getAnimationTime(name);
	}
	
	public List<Integer> getRevives() {
		return stats.getRevives();
	}

	public void setOverrideStats(MapleMonsterStats overrideStats) {
		this.overrideStats = overrideStats;
	}

	/**
	 * 
	 * @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;
		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 || isBoss()) {
						cattacker.getAttacker().getClient().getSession().write(MaplePacketCreator.showMonsterHP(getObjectId(), remhppercentage));
					}
				}
			}
		}
	}

	public boolean isAttackedBy(MapleCharacter chr) {
		for (AttackerEntry aentry : attackers) {
			if (aentry.contains(chr)) {
				return true;
			}
		}
		return false;
	}

	private void giveExpToCharacter(MapleCharacter attacker, int exp, boolean highestDamage, int numExpSharers) {
		if (highestDamage) {
			if (eventInstance != null) {
				eventInstance.monsterKilled(attacker, this);
			}
			highestDamageChar = attacker;
		}
		if (attacker.getHp() > 0) {
			if (exp > 0) {
				int personalExp = exp;
				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);
					}
				}
				attacker.gainExp(personalExp, true, false, highestDamage);
			}
			attacker.mobKilled(this.getId());
		}
	}

	public MapleCharacter killBy(MapleCharacter killer) {
		// broadcastMessage(null, MaplePacketCreator.getPreKillthis(this.getObjectId()));

		// update exp
		int totalBaseExp = this.getExp() * ChannelServer.getInstance(killer.getClient().getChannel()).getExpRate();
		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());
						reviveMap.spawnMonster(mob);
					}
				}
			}, this.getAnimationTime("die1") - MapleMonsterInformationProvider.APPROX_FADE_DELAY);
		}
		if (eventInstance != null) {
			eventInstance.unregisterMonster(this);
		}
		for (MonsterListener listener : listeners.toArray(new MonsterListener[listeners.size()])) {
			listener.monsterKilled(this, highestDamageChar);
		}
		return highestDamageChar;
	}

	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 controller = getController();
		if (controller == newController) {
			return;
		}
		if (controller != null) {
			controller.stopControllingMonster(this);
			controller.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() {
		return controllerHasAggro;
	}

	public void setControllerHasAggro(boolean controllerHasAggro) {
		this.controllerHasAggro = controllerHasAggro;
	}

	public boolean isControllerKnowsAboutAggro() {
		return controllerKnowsAboutAggro;
	}

	public void setControllerKnowsAboutAggro(boolean controllerKnowsAboutAggro) {
		this.controllerKnowsAboutAggro = controllerKnowsAboutAggro;
	}

	@Override
	public void sendSpawnData(MapleClient client) {
		if (!isAlive()) {
			return;
		}
		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);
			}
		}
	}

	@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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -