📄 maplemonster.java.svn-base
字号:
}
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 + -