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

📄 maplemonster.java.svn-base

📁 冒险岛私服Java版服务端(Odinms)源代码。学习JAVA开发的朋友
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
		}
		return stats.getEffectiveness(e);
	}
	
	public boolean applyStatus (MapleCharacter from, final MonsterStatusEffect status, boolean poison, long duration) {
		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...)
		if (status.getSkill().getId() == 2111006) { // fp compo
			ElementalEffectiveness effectiveness = stats.getEffectiveness(Element.POISON);
			if (effectiveness == ElementalEffectiveness.IMMUNE || effectiveness == ElementalEffectiveness.STRONG) {
				return false;
			}
		} else if (status.getSkill().getId() == 2211006) { // il compo
			ElementalEffectiveness effectiveness = stats.getEffectiveness(Element.ICE);
			if (effectiveness == ElementalEffectiveness.IMMUNE || effectiveness == ElementalEffectiveness.STRONG) {
				return false;
			}
		}
		if (poison && getHp() <= 1) {
			return false;
		}

		if (isBoss()) {
			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);
				}
				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 (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;
	}
	
	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;
		}
	}
}

⌨️ 快捷键说明

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