source
Source for my MapleSolaxiaV2 (v83 MapleStory).
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
import server.maps.AbstractAnimatedMapleMapObject;
|
||||
|
||||
public abstract class AbstractLoadedMapleLife extends AbstractAnimatedMapleMapObject {
|
||||
private final int id;
|
||||
private int f;
|
||||
private boolean hide;
|
||||
private int fh;
|
||||
private int start_fh;
|
||||
private int cy;
|
||||
private int rx0;
|
||||
private int rx1;
|
||||
|
||||
public AbstractLoadedMapleLife(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public AbstractLoadedMapleLife(AbstractLoadedMapleLife life) {
|
||||
this(life.getId());
|
||||
this.f = life.f;
|
||||
this.hide = life.hide;
|
||||
this.fh = life.fh;
|
||||
this.start_fh = life.fh;
|
||||
this.cy = life.cy;
|
||||
this.rx0 = life.rx0;
|
||||
this.rx1 = life.rx1;
|
||||
}
|
||||
|
||||
public int getF() {
|
||||
return f;
|
||||
}
|
||||
|
||||
public void setF(int f) {
|
||||
this.f = f;
|
||||
}
|
||||
|
||||
public boolean isHidden() {
|
||||
return hide;
|
||||
}
|
||||
|
||||
public void setHide(boolean hide) {
|
||||
this.hide = hide;
|
||||
}
|
||||
|
||||
public int getFh() {
|
||||
return fh;
|
||||
}
|
||||
|
||||
public void setFh(int fh) {
|
||||
this.fh = fh;
|
||||
}
|
||||
|
||||
public int getStartFh() {
|
||||
return start_fh;
|
||||
}
|
||||
|
||||
public int getCy() {
|
||||
return cy;
|
||||
}
|
||||
|
||||
public void setCy(int cy) {
|
||||
this.cy = cy;
|
||||
}
|
||||
|
||||
public int getRx0() {
|
||||
return rx0;
|
||||
}
|
||||
|
||||
public void setRx0(int rx0) {
|
||||
this.rx0 = rx0;
|
||||
}
|
||||
|
||||
public int getRx1() {
|
||||
return rx1;
|
||||
}
|
||||
|
||||
public void setRx1(int rx1) {
|
||||
this.rx1 = rx1;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
public enum Element {
|
||||
NEUTRAL, FIRE, ICE, LIGHTING, POISON, HOLY, DARK;
|
||||
|
||||
public static Element getFromChar(char c) {
|
||||
switch (Character.toUpperCase(c)) {
|
||||
case 'F':
|
||||
return FIRE;
|
||||
case 'I':
|
||||
return ICE;
|
||||
case 'L':
|
||||
return LIGHTING;
|
||||
case 'S':
|
||||
return POISON;
|
||||
case 'H':
|
||||
return HOLY;
|
||||
case 'D':
|
||||
return DARK;
|
||||
case 'P':
|
||||
return NEUTRAL;
|
||||
}
|
||||
throw new IllegalArgumentException("unknown elemnt char " + c);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
public enum ElementalEffectiveness {
|
||||
NORMAL, IMMUNE, STRONG, WEAK, NEUTRAL;
|
||||
|
||||
public static ElementalEffectiveness getByNumber(int num) {
|
||||
switch (num) {
|
||||
case 1:
|
||||
return IMMUNE;
|
||||
case 2:
|
||||
return STRONG;
|
||||
case 3:
|
||||
return WEAK;
|
||||
case 4:
|
||||
return NEUTRAL;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unkown effectiveness: " + num);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
import provider.MapleDataTool;
|
||||
import provider.wz.MapleDataType;
|
||||
import tools.Pair;
|
||||
import tools.StringUtil;
|
||||
|
||||
public class MapleLifeFactory {
|
||||
|
||||
private static MapleDataProvider data = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Mob.wz"));
|
||||
private final static MapleDataProvider stringDataWZ = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/String.wz"));
|
||||
private static MapleData mobStringData = stringDataWZ.getData("Mob.img");
|
||||
private static MapleData npcStringData = stringDataWZ.getData("Npc.img");
|
||||
private static Map<Integer, MapleMonsterStats> monsterStats = new HashMap<>();
|
||||
|
||||
public static AbstractLoadedMapleLife getLife(int id, String type) {
|
||||
if (type.equalsIgnoreCase("n")) {
|
||||
return getNPC(id);
|
||||
} else if (type.equalsIgnoreCase("m")) {
|
||||
return getMonster(id);
|
||||
} else {
|
||||
System.out.println("Unknown Life type: " + type);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static MapleMonster getMonster(int mid) {
|
||||
MapleMonsterStats stats = monsterStats.get(Integer.valueOf(mid));
|
||||
if (stats == null) {
|
||||
MapleData monsterData = data.getData(StringUtil.getLeftPaddedStr(Integer.toString(mid) + ".img", '0', 11));
|
||||
if (monsterData == null) {
|
||||
return null;
|
||||
}
|
||||
MapleData monsterInfoData = monsterData.getChildByPath("info");
|
||||
stats = new MapleMonsterStats();
|
||||
stats.setHp(MapleDataTool.getIntConvert("maxHP", monsterInfoData));
|
||||
stats.setFriendly(MapleDataTool.getIntConvert("damagedByMob", monsterInfoData, 0) == 1);
|
||||
stats.setPADamage(MapleDataTool.getIntConvert("PADamage", monsterInfoData));
|
||||
stats.setPDDamage(MapleDataTool.getIntConvert("PDDamage", monsterInfoData));
|
||||
stats.setMADamage(MapleDataTool.getIntConvert("MADamage", monsterInfoData));
|
||||
stats.setMDDamage(MapleDataTool.getIntConvert("MDDamage", monsterInfoData));
|
||||
stats.setMp(MapleDataTool.getIntConvert("maxMP", monsterInfoData, 0));
|
||||
stats.setExp(MapleDataTool.getIntConvert("exp", monsterInfoData, 0));
|
||||
stats.setLevel(MapleDataTool.getIntConvert("level", monsterInfoData));
|
||||
stats.setRemoveAfter(MapleDataTool.getIntConvert("removeAfter", monsterInfoData, 0));
|
||||
stats.setBoss(MapleDataTool.getIntConvert("boss", monsterInfoData, 0) > 0);
|
||||
stats.setExplosiveReward(MapleDataTool.getIntConvert("explosiveReward", monsterInfoData, 0) > 0);
|
||||
stats.setFfaLoot(MapleDataTool.getIntConvert("publicReward", monsterInfoData, 0) > 0);
|
||||
stats.setUndead(MapleDataTool.getIntConvert("undead", monsterInfoData, 0) > 0);
|
||||
stats.setName(MapleDataTool.getString(mid + "/name", mobStringData, "MISSINGNO"));
|
||||
stats.setBuffToGive(MapleDataTool.getIntConvert("buff", monsterInfoData, -1));
|
||||
stats.setCP(MapleDataTool.getIntConvert("getCP", monsterInfoData, 0));
|
||||
stats.setRemoveOnMiss(MapleDataTool.getIntConvert("removeOnMiss", monsterInfoData, 0) > 0);
|
||||
|
||||
MapleData special = monsterInfoData.getChildByPath("coolDamage");
|
||||
if (special != null) {
|
||||
int coolDmg = MapleDataTool.getIntConvert("coolDamage", monsterInfoData);
|
||||
int coolProb = MapleDataTool.getIntConvert("coolDamageProb", monsterInfoData, 0);
|
||||
stats.setCool(new Pair<>(coolDmg, coolProb));
|
||||
}
|
||||
special = monsterInfoData.getChildByPath("loseItem");
|
||||
if (special != null) {
|
||||
for (MapleData liData : special.getChildren()) {
|
||||
stats.addLoseItem(new loseItem(MapleDataTool.getInt(liData.getChildByPath("id")), (byte) MapleDataTool.getInt(liData.getChildByPath("prop")), (byte) MapleDataTool.getInt(liData.getChildByPath("x"))));
|
||||
}
|
||||
}
|
||||
special = monsterInfoData.getChildByPath("selfDestruction");
|
||||
if (special != null) {
|
||||
stats.setSelfDestruction(new selfDestruction((byte) MapleDataTool.getInt(special.getChildByPath("action")), MapleDataTool.getIntConvert("removeAfter", special, -1), MapleDataTool.getIntConvert("hp", special, -1)));
|
||||
}
|
||||
MapleData firstAttackData = monsterInfoData.getChildByPath("firstAttack");
|
||||
int firstAttack = 0;
|
||||
if (firstAttackData != null) {
|
||||
if (firstAttackData.getType() == MapleDataType.FLOAT) {
|
||||
firstAttack = Math.round(MapleDataTool.getFloat(firstAttackData));
|
||||
} else {
|
||||
firstAttack = MapleDataTool.getInt(firstAttackData);
|
||||
}
|
||||
}
|
||||
stats.setFirstAttack(firstAttack > 0);
|
||||
stats.setDropPeriod(MapleDataTool.getIntConvert("dropItemPeriod", monsterInfoData, 0) * 10000);
|
||||
|
||||
stats.setTagColor(MapleDataTool.getIntConvert("hpTagColor", monsterInfoData, 0));
|
||||
stats.setTagBgColor(MapleDataTool.getIntConvert("hpTagBgcolor", monsterInfoData, 0));
|
||||
|
||||
for (MapleData idata : monsterData) {
|
||||
if (!idata.getName().equals("info")) {
|
||||
int delay = 0;
|
||||
for (MapleData pic : idata.getChildren()) {
|
||||
delay += MapleDataTool.getIntConvert("delay", pic, 0);
|
||||
}
|
||||
stats.setAnimationTime(idata.getName(), delay);
|
||||
}
|
||||
}
|
||||
MapleData reviveInfo = monsterInfoData.getChildByPath("revive");
|
||||
if (reviveInfo != null) {
|
||||
List<Integer> revives = new LinkedList<>();
|
||||
for (MapleData data_ : reviveInfo) {
|
||||
revives.add(MapleDataTool.getInt(data_));
|
||||
}
|
||||
stats.setRevives(revives);
|
||||
}
|
||||
decodeElementalString(stats, MapleDataTool.getString("elemAttr", monsterInfoData, ""));
|
||||
MapleData monsterSkillData = monsterInfoData.getChildByPath("skill");
|
||||
if (monsterSkillData != null) {
|
||||
int i = 0;
|
||||
List<Pair<Integer, Integer>> skills = new ArrayList<>();
|
||||
while (monsterSkillData.getChildByPath(Integer.toString(i)) != null) {
|
||||
skills.add(new Pair<>(Integer.valueOf(MapleDataTool.getInt(i + "/skill", monsterSkillData, 0)), Integer.valueOf(MapleDataTool.getInt(i + "/level", monsterSkillData, 0))));
|
||||
i++;
|
||||
}
|
||||
stats.setSkills(skills);
|
||||
}
|
||||
MapleData banishData = monsterInfoData.getChildByPath("ban");
|
||||
if (banishData != null) {
|
||||
stats.setBanishInfo(new BanishInfo(MapleDataTool.getString("banMsg", banishData), MapleDataTool.getInt("banMap/0/field", banishData, -1), MapleDataTool.getString("banMap/0/portal", banishData, "sp")));
|
||||
}
|
||||
monsterStats.put(Integer.valueOf(mid), stats);
|
||||
}
|
||||
MapleMonster ret = new MapleMonster(mid, stats);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void decodeElementalString(MapleMonsterStats stats, String elemAttr) {
|
||||
for (int i = 0; i < elemAttr.length(); i += 2) {
|
||||
stats.setEffectiveness(Element.getFromChar(elemAttr.charAt(i)), ElementalEffectiveness.getByNumber(Integer.valueOf(String.valueOf(elemAttr.charAt(i + 1)))));
|
||||
}
|
||||
}
|
||||
|
||||
public static MapleNPC getNPC(int nid) {
|
||||
return new MapleNPC(nid, new MapleNPCStats(MapleDataTool.getString(nid + "/name", npcStringData, "MISSINGNO")));
|
||||
}
|
||||
|
||||
public static class BanishInfo {
|
||||
|
||||
private int map;
|
||||
private String portal, msg;
|
||||
|
||||
public BanishInfo(String msg, int map, String portal) {
|
||||
this.msg = msg;
|
||||
this.map = map;
|
||||
this.portal = portal;
|
||||
}
|
||||
|
||||
public int getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public String getPortal() {
|
||||
return portal;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
public static class loseItem {
|
||||
|
||||
private int id;
|
||||
private byte chance, x;
|
||||
|
||||
private loseItem(int id, byte chance, byte x) {
|
||||
this.id = id;
|
||||
this.chance = chance;
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public byte getChance() {
|
||||
return chance;
|
||||
}
|
||||
|
||||
public byte getX() {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
public static class selfDestruction {
|
||||
|
||||
private byte action;
|
||||
private int removeAfter;
|
||||
private int hp;
|
||||
|
||||
private selfDestruction(byte action, int removeAfter, int hp) {
|
||||
this.action = action;
|
||||
this.removeAfter = removeAfter;
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
public int getHp() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
public byte getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public int removeAfter() {
|
||||
return removeAfter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,954 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
import client.MapleBuffStat;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.MapleJob;
|
||||
import client.Skill;
|
||||
import client.SkillFactory;
|
||||
import client.status.MonsterStatus;
|
||||
import client.status.MonsterStatusEffect;
|
||||
import constants.ServerConstants;
|
||||
import constants.skills.FPMage;
|
||||
import constants.skills.Hermit;
|
||||
import constants.skills.ILMage;
|
||||
import constants.skills.NightLord;
|
||||
import constants.skills.NightWalker;
|
||||
import constants.skills.Shadower;
|
||||
import constants.skills.SuperGM;
|
||||
import java.awt.Point;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import net.server.world.MapleParty;
|
||||
import net.server.world.MaplePartyCharacter;
|
||||
import scripting.event.EventInstanceManager;
|
||||
import server.TimerManager;
|
||||
import server.life.MapleLifeFactory.BanishInfo;
|
||||
import server.maps.MapleMap;
|
||||
import server.maps.MapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.Randomizer;
|
||||
|
||||
public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
|
||||
private MapleMonsterStats stats;
|
||||
private int hp, mp;
|
||||
private WeakReference<MapleCharacter> controller = new WeakReference<>(null);
|
||||
private boolean controllerHasAggro, controllerKnowsAboutAggro;
|
||||
private EventInstanceManager eventInstance = null;
|
||||
private Collection<MonsterListener> listeners = new LinkedList<>();
|
||||
private EnumMap<MonsterStatus, MonsterStatusEffect> stati = new EnumMap<>(MonsterStatus.class);
|
||||
private ArrayList<MonsterStatus> alreadyBuffed = new ArrayList<MonsterStatus>();
|
||||
private MapleMap map;
|
||||
private int VenomMultiplier = 0;
|
||||
private boolean fake = false;
|
||||
private boolean dropsDisabled = false;
|
||||
private List<Pair<Integer, Integer>> usedSkills = new ArrayList<>();
|
||||
private Map<Pair<Integer, Integer>, Integer> skillsUsed = new HashMap<>();
|
||||
private List<Integer> stolenItems = new ArrayList<>();
|
||||
private int team;
|
||||
private final HashMap<Integer, AtomicInteger> takenDamage = new HashMap<>();
|
||||
|
||||
public ReentrantLock monsterLock = new ReentrantLock();
|
||||
|
||||
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 getHp() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
public void setHp(int hp) {
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
public int getMaxHp() {
|
||||
return stats.getHp();
|
||||
}
|
||||
|
||||
public int getMp() {
|
||||
return mp;
|
||||
}
|
||||
|
||||
public void setMp(int mp) {
|
||||
if (mp < 0) {
|
||||
mp = 0;
|
||||
}
|
||||
this.mp = mp;
|
||||
}
|
||||
|
||||
public int getMaxMp() {
|
||||
return stats.getMp();
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
return stats.getExp();
|
||||
}
|
||||
|
||||
int getLevel() {
|
||||
return stats.getLevel();
|
||||
}
|
||||
|
||||
public int getCP() {
|
||||
return stats.getCP();
|
||||
}
|
||||
|
||||
public int getTeam() {
|
||||
return team;
|
||||
}
|
||||
|
||||
public void setTeam(int team) {
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
public int getVenomMulti() {
|
||||
return this.VenomMultiplier;
|
||||
}
|
||||
|
||||
public void setVenomMulti(int multiplier) {
|
||||
this.VenomMultiplier = multiplier;
|
||||
}
|
||||
|
||||
public MapleMonsterStats getStats() {
|
||||
return stats;
|
||||
}
|
||||
|
||||
public boolean isBoss() {
|
||||
return stats.isBoss() || isHT();
|
||||
}
|
||||
|
||||
public int getAnimationTime(String name) {
|
||||
return stats.getAnimationTime(name);
|
||||
}
|
||||
|
||||
private List<Integer> getRevives() {
|
||||
return stats.getRevives();
|
||||
}
|
||||
|
||||
private byte getTagColor() {
|
||||
return stats.getTagColor();
|
||||
}
|
||||
|
||||
private byte getTagBgColor() {
|
||||
return stats.getTagBgColor();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param from the player that dealt the damage
|
||||
* @param damage
|
||||
*/
|
||||
public synchronized void damage(MapleCharacter from, int damage) { // may be pointless synchronization
|
||||
if (!isAlive()) {
|
||||
return;
|
||||
}
|
||||
int trueDamage = Math.min(hp, damage); // since magic happens otherwise B^)
|
||||
|
||||
if(ServerConstants.USE_DEBUG == true && from != null) from.dropMessage(5, "Hitted MOB " + this.getId());
|
||||
|
||||
hp -= damage;
|
||||
if (takenDamage.containsKey(from.getId())) {
|
||||
takenDamage.get(from.getId()).addAndGet(trueDamage);
|
||||
} else {
|
||||
takenDamage.put(from.getId(), new AtomicInteger(trueDamage));
|
||||
}
|
||||
|
||||
if (hasBossHPBar()) {
|
||||
from.getMap().broadcastMessage(makeBossHPBarPacket(), getPosition());
|
||||
} else if (!isBoss()) {
|
||||
int remainingHP = (int) Math.max(1, hp * 100f / getMaxHp());
|
||||
byte[] packet = MaplePacketCreator.showMonsterHP(getObjectId(), remainingHP);
|
||||
if (from.getParty() != null) {
|
||||
for (MaplePartyCharacter mpc : from.getParty().getMembers()) {
|
||||
MapleCharacter member = from.getMap().getCharacterById(mpc.getId()); // god bless
|
||||
if (member != null) {
|
||||
member.announce(packet.clone()); // clone it just in case of crypto
|
||||
}
|
||||
}
|
||||
} else {
|
||||
from.announce(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void heal(int hp, int mp) {
|
||||
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) {
|
||||
return takenDamage.containsKey(chr.getId());
|
||||
}
|
||||
|
||||
private void distributeExperienceToParty(int pid, int exp, int killer, Map<Integer, Integer> expDist) {
|
||||
LinkedList<MapleCharacter> members = new LinkedList<>();
|
||||
|
||||
map.getCharacterReadLock().lock();
|
||||
Collection<MapleCharacter> chrs = map.getCharacters();
|
||||
try {
|
||||
for (MapleCharacter mc : chrs) {
|
||||
if (mc.getPartyId() == pid) {
|
||||
members.add(mc);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
map.getCharacterReadLock().unlock();
|
||||
}
|
||||
|
||||
final int minLevel = getLevel() - 5;
|
||||
|
||||
int partyLevel = 0;
|
||||
int leechMinLevel = 0;
|
||||
|
||||
for (MapleCharacter mc : members) {
|
||||
if (mc.getLevel() >= minLevel) {
|
||||
leechMinLevel = Math.min(mc.getLevel() - 5, minLevel);
|
||||
}
|
||||
}
|
||||
|
||||
int leechCount = 0;
|
||||
for (MapleCharacter mc : members) {
|
||||
if (mc.getLevel() >= leechMinLevel) {
|
||||
partyLevel += mc.getLevel();
|
||||
leechCount++;
|
||||
}
|
||||
}
|
||||
|
||||
final int mostDamageCid = getHighestDamagerId();
|
||||
|
||||
for (MapleCharacter mc : members) {
|
||||
int id = mc.getId();
|
||||
int level = mc.getLevel();
|
||||
if (expDist.containsKey(id)
|
||||
|| level >= leechMinLevel) {
|
||||
boolean isKiller = killer == id;
|
||||
boolean mostDamage = mostDamageCid == id;
|
||||
int xp = (int) (exp * 0.80f * level / partyLevel);
|
||||
if (mostDamage) {
|
||||
xp += (exp * 0.20f);
|
||||
}
|
||||
giveExpToCharacter(mc, xp, isKiller, leechCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void distributeExperience(int killerId) {
|
||||
if (isAlive()) {
|
||||
return;
|
||||
}
|
||||
int exp = getExp();
|
||||
int totalHealth = getMaxHp();
|
||||
Map<Integer, Integer> expDist = new HashMap<>();
|
||||
Map<Integer, Integer> partyExp = new HashMap<>();
|
||||
// 80% of pool is split amongst all the damagers
|
||||
for (Entry<Integer, AtomicInteger> damage : takenDamage.entrySet()) {
|
||||
expDist.put(damage.getKey(), (int) (0.80f * exp * damage.getValue().get() / totalHealth));
|
||||
}
|
||||
map.getCharacterReadLock().lock(); // avoid concurrent mod
|
||||
Collection<MapleCharacter> chrs = map.getCharacters();
|
||||
try {
|
||||
for (MapleCharacter mc : chrs) {
|
||||
if (expDist.containsKey(mc.getId())) {
|
||||
boolean isKiller = mc.getId() == killerId;
|
||||
int xp = expDist.get(mc.getId());
|
||||
if (isKiller) {
|
||||
xp += exp / 5;
|
||||
}
|
||||
MapleParty p = mc.getParty();
|
||||
if (p != null) {
|
||||
int pID = p.getId();
|
||||
int pXP = xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
|
||||
partyExp.put(pID, pXP);
|
||||
} else {
|
||||
giveExpToCharacter(mc, xp, isKiller, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
map.getCharacterReadLock().unlock();
|
||||
}
|
||||
for (Entry<Integer, Integer> party : partyExp.entrySet()) {
|
||||
distributeExperienceToParty(party.getKey(), party.getValue(), killerId, expDist);
|
||||
}
|
||||
}
|
||||
|
||||
public void giveExpToCharacter(MapleCharacter attacker, int exp, boolean isKiller, int numExpSharers) {
|
||||
if (isKiller) {
|
||||
if (eventInstance != null) {
|
||||
eventInstance.monsterKilled(attacker, this);
|
||||
}
|
||||
}
|
||||
final int partyModifier = numExpSharers > 1 ? (110 + (5 * (numExpSharers - 2))) : 0;
|
||||
|
||||
int partyExp = 0;
|
||||
|
||||
if (attacker.getHp() > 0) {
|
||||
int personalExp = exp * attacker.getExpRate();
|
||||
|
||||
if (exp > 0) {
|
||||
if (partyModifier > 0) {
|
||||
partyExp = (int) (personalExp * ServerConstants.PARTY_EXPERIENCE_MOD * partyModifier / 1000f);
|
||||
}
|
||||
Integer holySymbol = attacker.getBuffedValue(MapleBuffStat.HOLY_SYMBOL);
|
||||
boolean GMHolySymbol = attacker.getBuffSource(MapleBuffStat.HOLY_SYMBOL) == SuperGM.HOLY_SYMBOL;
|
||||
if (holySymbol != null) {
|
||||
if (numExpSharers == 1 && !GMHolySymbol) {
|
||||
personalExp *= 1.0 + (holySymbol.doubleValue() / 500.0);
|
||||
} else {
|
||||
personalExp *= 1.0 + (holySymbol.doubleValue() / 100.0);
|
||||
}
|
||||
}
|
||||
if (stati.containsKey(MonsterStatus.SHOWDOWN)) {
|
||||
personalExp *= (stati.get(MonsterStatus.SHOWDOWN).getStati().get(MonsterStatus.SHOWDOWN).doubleValue() / 100.0 + 1.0);
|
||||
}
|
||||
}
|
||||
if (exp < 0) {//O.O ><
|
||||
personalExp = Integer.MAX_VALUE;
|
||||
}
|
||||
attacker.gainExp(personalExp, partyExp, true, false, isKiller);
|
||||
attacker.mobKilled(getId());
|
||||
attacker.increaseEquipExp(personalExp);//better place
|
||||
}
|
||||
}
|
||||
|
||||
public MapleCharacter killBy(MapleCharacter killer) {
|
||||
distributeExperience(killer != null ? killer.getId() : 0);
|
||||
|
||||
if (getController() != null) { // this can/should only happen when a hidden gm attacks the monster
|
||||
getController().getClient().announce(MaplePacketCreator.stopControllingMonster(this.getObjectId()));
|
||||
getController().stopControllingMonster(this);
|
||||
}
|
||||
|
||||
final List<Integer> toSpawn = this.getRevives(); // this doesn't work (?)
|
||||
if (toSpawn != null) {
|
||||
final MapleMap reviveMap = killer.getMap();
|
||||
if (toSpawn.contains(9300216) && reviveMap.getId() > 925000000 && reviveMap.getId() < 926000000) {
|
||||
reviveMap.broadcastMessage(MaplePacketCreator.playSound("Dojang/clear"));
|
||||
reviveMap.broadcastMessage(MaplePacketCreator.showEffect("dojang/end/clear"));
|
||||
}
|
||||
Pair<Integer, String> timeMob = reviveMap.getTimeMob();
|
||||
if (timeMob != null) {
|
||||
if (toSpawn.contains(timeMob.getLeft())) {
|
||||
reviveMap.broadcastMessage(MaplePacketCreator.serverNotice(6, timeMob.getRight()));
|
||||
}
|
||||
|
||||
if (timeMob.getLeft() == 9300338 && (reviveMap.getId() >= 922240100 && reviveMap.getId() <= 922240119)) {
|
||||
if (!reviveMap.containsNPC(9001108)) {
|
||||
MapleNPC npc = MapleLifeFactory.getNPC(9001108);
|
||||
npc.setPosition(new Point(172, 9));
|
||||
npc.setCy(9);
|
||||
npc.setRx0(172 + 50);
|
||||
npc.setRx1(172 - 50);
|
||||
npc.setFh(27);
|
||||
reviveMap.addMapObject(npc);
|
||||
reviveMap.broadcastMessage(MaplePacketCreator.spawnNPC(npc));
|
||||
} else {
|
||||
reviveMap.toggleHiddenNPC(9001108);
|
||||
}
|
||||
}
|
||||
}
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Integer mid : toSpawn) {
|
||||
final MapleMonster mob = MapleLifeFactory.getMonster(mid);
|
||||
mob.setPosition(getPosition());
|
||||
if (dropsDisabled()) {
|
||||
mob.disableDrops();
|
||||
}
|
||||
reviveMap.spawnMonster(mob);
|
||||
}
|
||||
}
|
||||
}, getAnimationTime("die1"));
|
||||
}
|
||||
if (eventInstance != null) {
|
||||
if (!this.getStats().isFriendly()) {
|
||||
eventInstance.monsterKilled(this);
|
||||
}
|
||||
}
|
||||
// idk V just a troll
|
||||
for (MonsterListener listener : listeners.toArray(new MonsterListener[listeners.size()])) {
|
||||
listener.monsterKilled(getAnimationTime("die1"));
|
||||
}
|
||||
|
||||
MapleCharacter looter = map.getCharacterById(getHighestDamagerId());
|
||||
|
||||
return looter != null ? looter : killer;
|
||||
}
|
||||
|
||||
// should only really be used to determine drop owner
|
||||
private int getHighestDamagerId() {
|
||||
int curId = 0;
|
||||
int curDmg = 0;
|
||||
|
||||
for (Entry<Integer, AtomicInteger> damage : takenDamage.entrySet()) {
|
||||
curId = damage.getValue().get() >= curDmg ? damage.getKey() : curId;
|
||||
curDmg = damage.getKey() == curId ? damage.getValue().get() : curDmg;
|
||||
}
|
||||
|
||||
return curId;
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
return this.hp > 0;
|
||||
}
|
||||
|
||||
public MapleCharacter getController() {
|
||||
return controller.get();
|
||||
}
|
||||
|
||||
public void setController(MapleCharacter controller) {
|
||||
this.controller = new WeakReference<>(controller);
|
||||
}
|
||||
|
||||
public void switchController(MapleCharacter newController, boolean immediateAggro) {
|
||||
MapleCharacter controllers = getController();
|
||||
if (controllers == newController) {
|
||||
return;
|
||||
}
|
||||
if (controllers != null) {
|
||||
controllers.stopControllingMonster(this);
|
||||
controllers.getClient().announce(MaplePacketCreator.stopControllingMonster(getObjectId()));
|
||||
}
|
||||
newController.controlMonster(this, immediateAggro);
|
||||
setController(newController);
|
||||
if (immediateAggro) {
|
||||
setControllerHasAggro(true);
|
||||
}
|
||||
setControllerKnowsAboutAggro(false);
|
||||
}
|
||||
|
||||
public void addListener(MonsterListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public boolean isControllerHasAggro() {
|
||||
return fake ? false : controllerHasAggro;
|
||||
}
|
||||
|
||||
public void setControllerHasAggro(boolean controllerHasAggro) {
|
||||
if (fake) {
|
||||
return;
|
||||
}
|
||||
this.controllerHasAggro = controllerHasAggro;
|
||||
}
|
||||
|
||||
public boolean isControllerKnowsAboutAggro() {
|
||||
return fake ? false : controllerKnowsAboutAggro;
|
||||
}
|
||||
|
||||
public void setControllerKnowsAboutAggro(boolean controllerKnowsAboutAggro) {
|
||||
if (fake) {
|
||||
return;
|
||||
}
|
||||
this.controllerKnowsAboutAggro = controllerKnowsAboutAggro;
|
||||
}
|
||||
|
||||
public byte[] makeBossHPBarPacket() {
|
||||
return MaplePacketCreator.showBossHP(getId(), getHp(), getMaxHp(), getTagColor(), getTagBgColor());
|
||||
}
|
||||
|
||||
public boolean hasBossHPBar() {
|
||||
return (isBoss() && getTagColor() > 0) || isHT();
|
||||
}
|
||||
|
||||
private boolean isHT() {
|
||||
return getId() == 8810018;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSpawnData(MapleClient c) {
|
||||
if (!isAlive()) {
|
||||
return;
|
||||
}
|
||||
if (isFake()) {
|
||||
c.announce(MaplePacketCreator.spawnFakeMonster(this, 0));
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.spawnMonster(this, false));
|
||||
}
|
||||
if (stati.size() > 0) {
|
||||
for (final MonsterStatusEffect mse : this.stati.values()) {
|
||||
c.announce(MaplePacketCreator.applyMonsterStatus(getObjectId(), mse, null));
|
||||
}
|
||||
}
|
||||
if (hasBossHPBar()) {
|
||||
if (this.getMap().countMonster(8810026) > 0 && this.getMap().getId() == 240060200) {
|
||||
this.getMap().killAllMonsters();
|
||||
return;
|
||||
}
|
||||
c.announce(makeBossHPBarPacket());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendDestroyData(MapleClient client) {
|
||||
client.announce(MaplePacketCreator.killMonster(getObjectId(), false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapleMapObjectType getType() {
|
||||
return MapleMapObjectType.MONSTER;
|
||||
}
|
||||
|
||||
public void setEventInstance(EventInstanceManager eventInstance) {
|
||||
this.eventInstance = eventInstance;
|
||||
}
|
||||
|
||||
public EventInstanceManager getEventInstance() {
|
||||
return eventInstance;
|
||||
}
|
||||
|
||||
public boolean isMobile() {
|
||||
return stats.isMobile();
|
||||
}
|
||||
|
||||
public ElementalEffectiveness getEffectiveness(Element e) {
|
||||
if (stati.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:
|
||||
case NEUTRAL:
|
||||
return false;
|
||||
case NORMAL:
|
||||
case WEAK:
|
||||
break;
|
||||
default: {
|
||||
System.out.println("Unknown elemental effectiveness: " + stats.getEffectiveness(status.getSkill().getElement()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (status.getSkill().getId() == FPMage.ELEMENT_COMPOSITION) { // fp compo
|
||||
ElementalEffectiveness effectiveness = stats.getEffectiveness(Element.POISON);
|
||||
if (effectiveness == ElementalEffectiveness.IMMUNE || effectiveness == ElementalEffectiveness.STRONG) {
|
||||
return false;
|
||||
}
|
||||
} else if (status.getSkill().getId() == ILMage.ELEMENT_COMPOSITION) { // il compo
|
||||
ElementalEffectiveness effectiveness = stats.getEffectiveness(Element.ICE);
|
||||
if (effectiveness == ElementalEffectiveness.IMMUNE || effectiveness == ElementalEffectiveness.STRONG) {
|
||||
return false;
|
||||
}
|
||||
} else if (status.getSkill().getId() == NightLord.VENOMOUS_STAR || status.getSkill().getId() == Shadower.VENOMOUS_STAB || status.getSkill().getId() == NightWalker.VENOM) {// venom
|
||||
if (stats.getEffectiveness(Element.POISON) == ElementalEffectiveness.WEAK) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (poison && getHp() <= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Map<MonsterStatus, Integer> statis = status.getStati();
|
||||
if (stats.isBoss()) {
|
||||
if (!(statis.containsKey(MonsterStatus.SPEED)
|
||||
&& statis.containsKey(MonsterStatus.NINJA_AMBUSH)
|
||||
&& statis.containsKey(MonsterStatus.WATK))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (MonsterStatus stat : statis.keySet()) {
|
||||
final MonsterStatusEffect oldEffect = stati.get(stat);
|
||||
if (oldEffect != null) {
|
||||
oldEffect.removeActiveStatus(stat);
|
||||
if (oldEffect.getStati().isEmpty()) {
|
||||
oldEffect.cancelTask();
|
||||
oldEffect.cancelDamageSchedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TimerManager timerManager = TimerManager.getInstance();
|
||||
final Runnable cancelTask = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (isAlive()) {
|
||||
byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), status.getStati());
|
||||
map.broadcastMessage(packet, getPosition());
|
||||
if (getController() != null && !getController().isMapObjectVisible(MapleMonster.this)) {
|
||||
getController().getClient().announce(packet);
|
||||
}
|
||||
}
|
||||
for (MonsterStatus stat : status.getStati().keySet()) {
|
||||
stati.remove(stat);
|
||||
}
|
||||
setVenomMulti(0);
|
||||
status.cancelDamageSchedule();
|
||||
}
|
||||
};
|
||||
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.setDamageSchedule(timerManager.register(new DamageTask(poisonDamage, from, status, cancelTask, 0), 1000, 1000));
|
||||
} else if (venom) {
|
||||
if (from.getJob() == MapleJob.NIGHTLORD || from.getJob() == MapleJob.SHADOWER || from.getJob().isA(MapleJob.NIGHTWALKER3)) {
|
||||
int poisonLevel, matk, id = from.getJob().getId();
|
||||
int skill = (id == 412 ? NightLord.VENOMOUS_STAR : (id == 422 ? Shadower.VENOMOUS_STAB : NightWalker.VENOM));
|
||||
poisonLevel = from.getSkillLevel(SkillFactory.getSkill(skill));
|
||||
if (poisonLevel <= 0) {
|
||||
return false;
|
||||
}
|
||||
matk = SkillFactory.getSkill(skill).getEffect(poisonLevel).getMatk();
|
||||
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 += (Randomizer.nextInt(gap) + minDmg);
|
||||
}
|
||||
poisonDamage = Math.min(Short.MAX_VALUE, poisonDamage);
|
||||
status.setValue(MonsterStatus.VENOMOUS_WEAPON, Integer.valueOf(poisonDamage));
|
||||
status.setDamageSchedule(timerManager.register(new DamageTask(poisonDamage, from, status, cancelTask, 0), 1000, 1000));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (status.getSkill().getId() == Hermit.SHADOW_WEB || status.getSkill().getId() == NightWalker.SHADOW_WEB) { //Shadow Web
|
||||
status.setDamageSchedule(timerManager.schedule(new DamageTask((int) (getMaxHp() / 50.0 + 0.999), from, status, cancelTask, 1), 3500));
|
||||
} else if (status.getSkill().getId() == 4121004 || status.getSkill().getId() == 4221004) { // Ninja Ambush
|
||||
final Skill skill = SkillFactory.getSkill(status.getSkill().getId());
|
||||
final byte level = from.getSkillLevel(skill);
|
||||
final int damage = (int) ((from.getStr() + from.getLuk()) * (1.5 + (level * 0.05)) * skill.getEffect(level).getDamage());
|
||||
/*if (getHp() - damage <= 1) { make hp 1 betch
|
||||
damage = getHp() - (getHp() - 1);
|
||||
}*/
|
||||
|
||||
status.setValue(MonsterStatus.NINJA_AMBUSH, Integer.valueOf(damage));
|
||||
status.setDamageSchedule(timerManager.register(new DamageTask(damage, from, status, cancelTask, 2), 1000, 1000));
|
||||
}
|
||||
for (MonsterStatus stat : status.getStati().keySet()) {
|
||||
stati.put(stat, status);
|
||||
alreadyBuffed.add(stat);
|
||||
}
|
||||
int animationTime = status.getSkill().getAnimationTime();
|
||||
byte[] packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), status, null);
|
||||
map.broadcastMessage(packet, getPosition());
|
||||
if (getController() != null && !getController().isMapObjectVisible(this)) {
|
||||
getController().getClient().announce(packet);
|
||||
}
|
||||
status.setCancelTask(timerManager.schedule(cancelTask, duration + animationTime));
|
||||
return true;
|
||||
}
|
||||
|
||||
public void applyMonsterBuff(final Map<MonsterStatus, Integer> stats, final int x, int skillId, long duration, MobSkill skill, final List<Integer> reflection) {
|
||||
TimerManager timerManager = TimerManager.getInstance();
|
||||
final Runnable cancelTask = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (isAlive()) {
|
||||
byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), stats);
|
||||
map.broadcastMessage(packet, getPosition());
|
||||
if (getController() != null && !getController().isMapObjectVisible(MapleMonster.this)) {
|
||||
getController().getClient().announce(packet);
|
||||
}
|
||||
for (final MonsterStatus stat : stats.keySet()) {
|
||||
stati.remove(stat);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
final MonsterStatusEffect effect = new MonsterStatusEffect(stats, null, skill, true);
|
||||
byte[] packet = MaplePacketCreator.applyMonsterStatus(getObjectId(), effect, reflection);
|
||||
map.broadcastMessage(packet, getPosition());
|
||||
for (MonsterStatus stat : stats.keySet()) {
|
||||
stati.put(stat, effect);
|
||||
alreadyBuffed.add(stat);
|
||||
}
|
||||
if (getController() != null && !getController().isMapObjectVisible(this)) {
|
||||
getController().getClient().announce(packet);
|
||||
}
|
||||
effect.setCancelTask(timerManager.schedule(cancelTask, duration));
|
||||
}
|
||||
|
||||
public void debuffMob(int skillid) {
|
||||
//skillid is not going to be used for now until I get warrior debuff working
|
||||
MonsterStatus[] stats = {MonsterStatus.WEAPON_ATTACK_UP, MonsterStatus.WEAPON_DEFENSE_UP, MonsterStatus.MAGIC_ATTACK_UP, MonsterStatus.MAGIC_DEFENSE_UP};
|
||||
for (int i = 0; i < stats.length; i++) {
|
||||
if (isBuffed(stats[i])) {
|
||||
final MonsterStatusEffect oldEffect = stati.get(stats[i]);
|
||||
byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), oldEffect.getStati());
|
||||
map.broadcastMessage(packet, getPosition());
|
||||
if (getController() != null && !getController().isMapObjectVisible(MapleMonster.this)) {
|
||||
getController().getClient().announce(packet);
|
||||
}
|
||||
stati.remove(stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBuffed(MonsterStatus status) {
|
||||
return stati.containsKey(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 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<>(toUse.getSkillId(), toUse.getSkillLevel()))) {
|
||||
int times = this.skillsUsed.get(new Pair<>(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<>(skillId, level));
|
||||
if (this.skillsUsed.containsKey(new Pair<>(skillId, level))) {
|
||||
int times = this.skillsUsed.get(new Pair<>(skillId, level)) + 1;
|
||||
this.skillsUsed.remove(new Pair<>(skillId, level));
|
||||
this.skillsUsed.put(new Pair<>(skillId, level), times);
|
||||
} else {
|
||||
this.skillsUsed.put(new Pair<>(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();
|
||||
}
|
||||
|
||||
private final class DamageTask implements Runnable {
|
||||
|
||||
private final int dealDamage;
|
||||
private final MapleCharacter chr;
|
||||
private final MonsterStatusEffect status;
|
||||
private final Runnable cancelTask;
|
||||
private final int type;
|
||||
private final MapleMap map;
|
||||
|
||||
private DamageTask(int dealDamage, MapleCharacter chr, MonsterStatusEffect status, Runnable cancelTask, int type) {
|
||||
this.dealDamage = dealDamage;
|
||||
this.chr = chr;
|
||||
this.status = status;
|
||||
this.cancelTask = cancelTask;
|
||||
this.type = type;
|
||||
this.map = chr.getMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int damage = dealDamage;
|
||||
if (damage >= hp) {
|
||||
damage = hp - 1;
|
||||
if (type == 1 || type == 2) {
|
||||
map.broadcastMessage(MaplePacketCreator.damageMonster(getObjectId(), damage), getPosition());
|
||||
cancelTask.run();
|
||||
status.getCancelTask().cancel(false);
|
||||
}
|
||||
}
|
||||
if (hp > 1 && damage > 0) {
|
||||
damage(chr, damage);
|
||||
if (type == 1) {
|
||||
map.broadcastMessage(MaplePacketCreator.damageMonster(getObjectId(), damage), getPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return stats.getName();
|
||||
}
|
||||
|
||||
public void addStolen(int itemId) {
|
||||
stolenItems.add(itemId);
|
||||
}
|
||||
|
||||
public List<Integer> getStolen() {
|
||||
return stolenItems;
|
||||
}
|
||||
|
||||
public void setTempEffectiveness(Element e, ElementalEffectiveness ee, long milli) {
|
||||
final Element fE = e;
|
||||
final ElementalEffectiveness fEE = stats.getEffectiveness(e);
|
||||
if (!stats.getEffectiveness(e).equals(ElementalEffectiveness.WEAK)) {
|
||||
stats.setEffectiveness(e, ee);
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
stats.removeEffectiveness(fE);
|
||||
stats.setEffectiveness(fE, fEE);
|
||||
}
|
||||
}, milli);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<MonsterStatus> alreadyBuffedStats() {
|
||||
return Collections.unmodifiableCollection(alreadyBuffed);
|
||||
}
|
||||
|
||||
public BanishInfo getBanish() {
|
||||
return stats.getBanishInfo();
|
||||
}
|
||||
|
||||
public void setBoss(boolean boss) {
|
||||
this.stats.setBoss(boss);
|
||||
}
|
||||
|
||||
public int getDropPeriodTime() {
|
||||
return stats.getDropPeriod();
|
||||
}
|
||||
|
||||
public int getPADamage() {
|
||||
return stats.getPADamage();
|
||||
}
|
||||
|
||||
public Map<MonsterStatus, MonsterStatusEffect> getStati() {
|
||||
return stati;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 ~ 2010 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
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 server.life;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
import provider.MapleDataTool;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.Pair;
|
||||
|
||||
public class MapleMonsterInformationProvider {
|
||||
// Author : LightPepsi
|
||||
|
||||
private static final MapleMonsterInformationProvider instance = new MapleMonsterInformationProvider();
|
||||
private final Map<Integer, List<MonsterDropEntry>> drops = new HashMap<>();
|
||||
private final List<MonsterGlobalDropEntry> globaldrops = new ArrayList<>();
|
||||
|
||||
protected MapleMonsterInformationProvider() {
|
||||
retrieveGlobal();
|
||||
}
|
||||
|
||||
public static MapleMonsterInformationProvider getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public final List<MonsterGlobalDropEntry> getGlobalDrop() {
|
||||
return globaldrops;
|
||||
}
|
||||
|
||||
private void retrieveGlobal() {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
try {
|
||||
final Connection con = DatabaseConnection.getConnection();
|
||||
ps = con.prepareStatement("SELECT * FROM drop_data_global WHERE chance > 0");
|
||||
rs = ps.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
globaldrops.add(
|
||||
new MonsterGlobalDropEntry(
|
||||
rs.getInt("itemid"),
|
||||
rs.getInt("chance"),
|
||||
rs.getInt("continent"),
|
||||
rs.getByte("dropType"),
|
||||
rs.getInt("minimum_quantity"),
|
||||
rs.getInt("maximum_quantity"),
|
||||
rs.getShort("questid")));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
System.err.println("Error retrieving drop" + e);
|
||||
} finally {
|
||||
try {
|
||||
if (ps != null) {
|
||||
ps.close();
|
||||
}
|
||||
if (rs != null) {
|
||||
rs.close();
|
||||
}
|
||||
} catch (SQLException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final List<MonsterDropEntry> retrieveDrop(final int monsterId) {
|
||||
if (drops.containsKey(monsterId)) {
|
||||
return drops.get(monsterId);
|
||||
}
|
||||
final List<MonsterDropEntry> ret = new LinkedList<>();
|
||||
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
ps = DatabaseConnection.getConnection().prepareStatement("SELECT * FROM drop_data WHERE dropperid = ?");
|
||||
ps.setInt(1, monsterId);
|
||||
rs = ps.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
ret.add(
|
||||
new MonsterDropEntry(
|
||||
rs.getInt("itemid"),
|
||||
rs.getInt("chance"),
|
||||
rs.getInt("minimum_quantity"),
|
||||
rs.getInt("maximum_quantity"),
|
||||
rs.getShort("questid")));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
return ret;
|
||||
} finally {
|
||||
try {
|
||||
if (ps != null) {
|
||||
ps.close();
|
||||
}
|
||||
if (rs != null) {
|
||||
rs.close();
|
||||
}
|
||||
} catch (SQLException ignore) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
drops.put(monsterId, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static ArrayList<Pair<Integer, String>> getMobsIDsFromName(String search)
|
||||
{
|
||||
MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File("wz/String.wz"));
|
||||
ArrayList<Pair<Integer, String>> retMobs = new ArrayList<Pair<Integer, String>>();
|
||||
MapleData data = dataProvider.getData("Mob.img");
|
||||
List<Pair<Integer, String>> mobPairList = new LinkedList<Pair<Integer, String>>();
|
||||
for (MapleData mobIdData : data.getChildren()) {
|
||||
int mobIdFromData = Integer.parseInt(mobIdData.getName());
|
||||
String mobNameFromData = MapleDataTool.getString(mobIdData.getChildByPath("name"), "NO-NAME");
|
||||
mobPairList.add(new Pair<Integer, String>(mobIdFromData, mobNameFromData));
|
||||
}
|
||||
for (Pair<Integer, String> mobPair : mobPairList) {
|
||||
if (mobPair.getRight().toLowerCase().contains(search.toLowerCase())) {
|
||||
retMobs.add(mobPair);
|
||||
}
|
||||
}
|
||||
return retMobs;
|
||||
}
|
||||
|
||||
public static String getMobNameFromID(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
return MapleLifeFactory.getMonster(id).getName();
|
||||
} catch (Exception e)
|
||||
{
|
||||
return null; //nonexistant mob
|
||||
}
|
||||
}
|
||||
|
||||
public final void clearDrops() {
|
||||
drops.clear();
|
||||
globaldrops.clear();
|
||||
retrieveGlobal();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import server.life.MapleLifeFactory.BanishInfo;
|
||||
import server.life.MapleLifeFactory.loseItem;
|
||||
import server.life.MapleLifeFactory.selfDestruction;
|
||||
import tools.Pair;
|
||||
|
||||
/**
|
||||
* @author Frz
|
||||
*/
|
||||
public class MapleMonsterStats {
|
||||
private int exp, hp, mp, level, PADamage, PDDamage, MADamage, MDDamage, dropPeriod, cp, buffToGive, removeAfter;
|
||||
private boolean boss, undead, ffaLoot, isExplosiveReward, firstAttack, removeOnMiss;
|
||||
private String name;
|
||||
private Map<String, Integer> animationTimes = new HashMap<String, Integer>();
|
||||
private Map<Element, ElementalEffectiveness> resistance = new HashMap<Element, ElementalEffectiveness>();
|
||||
private List<Integer> revives = Collections.emptyList();
|
||||
private byte tagColor, tagBgColor;
|
||||
private List<Pair<Integer, Integer>> skills = new ArrayList<Pair<Integer, Integer>>();
|
||||
private Pair<Integer, Integer> cool = null;
|
||||
private BanishInfo banish = null;
|
||||
private List<loseItem> loseItem = null;
|
||||
private selfDestruction selfDestruction = null;
|
||||
private boolean friendly;
|
||||
|
||||
public int getExp() {
|
||||
return exp;
|
||||
}
|
||||
|
||||
public void setExp(int exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public int getHp() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
public void setHp(int hp) {
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
public int getMp() {
|
||||
return mp;
|
||||
}
|
||||
|
||||
public void setMp(int mp) {
|
||||
this.mp = mp;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public int removeAfter() {
|
||||
return removeAfter;
|
||||
}
|
||||
|
||||
public void setRemoveAfter(int removeAfter) {
|
||||
this.removeAfter = removeAfter;
|
||||
}
|
||||
|
||||
public int getDropPeriod() {
|
||||
return dropPeriod;
|
||||
}
|
||||
|
||||
public void setDropPeriod(int dropPeriod) {
|
||||
this.dropPeriod = dropPeriod;
|
||||
}
|
||||
|
||||
public void setBoss(boolean boss) {
|
||||
this.boss = boss;
|
||||
}
|
||||
|
||||
public boolean isBoss() {
|
||||
return boss;
|
||||
}
|
||||
|
||||
public void setFfaLoot(boolean ffaLoot) {
|
||||
this.ffaLoot = ffaLoot;
|
||||
}
|
||||
|
||||
public boolean isFfaLoot() {
|
||||
return ffaLoot;
|
||||
}
|
||||
|
||||
public void setAnimationTime(String name, int delay) {
|
||||
animationTimes.put(name, delay);
|
||||
}
|
||||
|
||||
public int getAnimationTime(String name) {
|
||||
Integer ret = animationTimes.get(name);
|
||||
if (ret == null) {
|
||||
return 500;
|
||||
}
|
||||
return ret.intValue();
|
||||
}
|
||||
|
||||
public boolean isMobile() {
|
||||
return animationTimes.containsKey("move") || animationTimes.containsKey("fly");
|
||||
}
|
||||
|
||||
public List<Integer> getRevives() {
|
||||
return revives;
|
||||
}
|
||||
|
||||
public void setRevives(List<Integer> revives) {
|
||||
this.revives = revives;
|
||||
}
|
||||
|
||||
public void setUndead(boolean undead) {
|
||||
this.undead = undead;
|
||||
}
|
||||
|
||||
public boolean getUndead() {
|
||||
return undead;
|
||||
}
|
||||
|
||||
public void setEffectiveness(Element e, ElementalEffectiveness ee) {
|
||||
resistance.put(e, ee);
|
||||
}
|
||||
|
||||
public ElementalEffectiveness getEffectiveness(Element e) {
|
||||
ElementalEffectiveness elementalEffectiveness = resistance.get(e);
|
||||
if (elementalEffectiveness == null) {
|
||||
return ElementalEffectiveness.NORMAL;
|
||||
} else {
|
||||
return elementalEffectiveness;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public byte getTagColor() {
|
||||
return tagColor;
|
||||
}
|
||||
|
||||
public void setTagColor(int tagColor) {
|
||||
this.tagColor = (byte) tagColor;
|
||||
}
|
||||
|
||||
public byte getTagBgColor() {
|
||||
return tagBgColor;
|
||||
}
|
||||
|
||||
public void setTagBgColor(int tagBgColor) {
|
||||
this.tagBgColor = (byte) tagBgColor;
|
||||
}
|
||||
|
||||
public void setSkills(List<Pair<Integer, Integer>> skills) {
|
||||
for (Pair<Integer, Integer> skill : skills) {
|
||||
this.skills.add(skill);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Pair<Integer, Integer>> getSkills() {
|
||||
return Collections.unmodifiableList(this.skills);
|
||||
}
|
||||
|
||||
public int getNoSkills() {
|
||||
return this.skills.size();
|
||||
}
|
||||
|
||||
public boolean hasSkill(int skillId, int level) {
|
||||
for (Pair<Integer, Integer> skill : skills) {
|
||||
if (skill.getLeft() == skillId && skill.getRight() == level) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setFirstAttack(boolean firstAttack) {
|
||||
this.firstAttack = firstAttack;
|
||||
}
|
||||
|
||||
public boolean isFirstAttack() {
|
||||
return firstAttack;
|
||||
}
|
||||
|
||||
public void setBuffToGive(int buff) {
|
||||
this.buffToGive = buff;
|
||||
}
|
||||
|
||||
public int getBuffToGive() {
|
||||
return buffToGive;
|
||||
}
|
||||
|
||||
void removeEffectiveness(Element e) {
|
||||
resistance.remove(e);
|
||||
}
|
||||
|
||||
public BanishInfo getBanishInfo() {
|
||||
return banish;
|
||||
}
|
||||
|
||||
public void setBanishInfo(BanishInfo banish) {
|
||||
this.banish = banish;
|
||||
}
|
||||
|
||||
public int getPADamage() {
|
||||
return PADamage;
|
||||
}
|
||||
|
||||
public void setPADamage(int PADamage) {
|
||||
this.PADamage = PADamage;
|
||||
}
|
||||
|
||||
public int getCP() {
|
||||
return cp;
|
||||
}
|
||||
|
||||
public void setCP(int cp) {
|
||||
this.cp = cp;
|
||||
}
|
||||
|
||||
public List<loseItem> loseItem() {
|
||||
return loseItem;
|
||||
}
|
||||
|
||||
public void addLoseItem(loseItem li) {
|
||||
if (loseItem == null) {
|
||||
loseItem = new LinkedList<loseItem>();
|
||||
}
|
||||
loseItem.add(li);
|
||||
}
|
||||
|
||||
public selfDestruction selfDestruction() {
|
||||
return selfDestruction;
|
||||
}
|
||||
|
||||
public void setSelfDestruction(selfDestruction sd) {
|
||||
this.selfDestruction = sd;
|
||||
}
|
||||
|
||||
public void setExplosiveReward(boolean isExplosiveReward) {
|
||||
this.isExplosiveReward = isExplosiveReward;
|
||||
}
|
||||
|
||||
public boolean isExplosiveReward() {
|
||||
return isExplosiveReward;
|
||||
}
|
||||
|
||||
public void setRemoveOnMiss(boolean removeOnMiss) {
|
||||
this.removeOnMiss = removeOnMiss;
|
||||
}
|
||||
|
||||
public boolean removeOnMiss() {
|
||||
return removeOnMiss;
|
||||
}
|
||||
|
||||
public void setCool(Pair<Integer, Integer> cool) {
|
||||
this.cool = cool;
|
||||
}
|
||||
|
||||
public Pair<Integer, Integer> getCool() {
|
||||
return cool;
|
||||
}
|
||||
|
||||
public int getPDDamage() {
|
||||
return PDDamage;
|
||||
}
|
||||
|
||||
public int getMADamage() {
|
||||
return MADamage;
|
||||
}
|
||||
|
||||
public int getMDDamage() {
|
||||
return MDDamage;
|
||||
}
|
||||
|
||||
public boolean isFriendly() {
|
||||
return friendly;
|
||||
}
|
||||
|
||||
public void setFriendly(boolean value) {
|
||||
this.friendly = value;
|
||||
}
|
||||
|
||||
public void setPDDamage(int PDDamage) {
|
||||
this.PDDamage = PDDamage;
|
||||
}
|
||||
|
||||
public void setMADamage(int MADamage) {
|
||||
this.MADamage = MADamage;
|
||||
}
|
||||
|
||||
public void setMDDamage(int MDDamage) {
|
||||
this.MDDamage = MDDamage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
import client.MapleClient;
|
||||
import server.MapleShopFactory;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
public class MapleNPC extends AbstractLoadedMapleLife {
|
||||
private MapleNPCStats stats;
|
||||
|
||||
public MapleNPC(int id, MapleNPCStats stats) {
|
||||
super(id);
|
||||
this.stats = stats;
|
||||
}
|
||||
|
||||
public boolean hasShop() {
|
||||
return MapleShopFactory.getInstance().getShopForNPC(getId()) != null;
|
||||
}
|
||||
|
||||
public void sendShop(MapleClient c) {
|
||||
MapleShopFactory.getInstance().getShopForNPC(getId()).sendShop(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSpawnData(MapleClient client) {
|
||||
if (this.getId() > 9010010 && this.getId() < 9010014) {
|
||||
client.announce(MaplePacketCreator.spawnNPCRequestController(this, false));
|
||||
} else {
|
||||
client.announce(MaplePacketCreator.spawnNPC(this));
|
||||
client.announce(MaplePacketCreator.spawnNPCRequestController(this, true));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendDestroyData(MapleClient client) {
|
||||
client.announce(MaplePacketCreator.removeNPC(getObjectId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapleMapObjectType getType() {
|
||||
return MapleMapObjectType.NPC;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return stats.getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Matze
|
||||
*/
|
||||
public class MapleNPCStats {
|
||||
private String name;
|
||||
|
||||
public MapleNPCStats(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Danny (Leifde)
|
||||
*/
|
||||
public class MobAttackInfo {
|
||||
private boolean isDeadlyAttack;
|
||||
private int mpBurn;
|
||||
private int diseaseSkill;
|
||||
private int diseaseLevel;
|
||||
private int mpCon;
|
||||
|
||||
public MobAttackInfo(int mobId, int attackId) {
|
||||
}
|
||||
|
||||
public void setDeadlyAttack(boolean isDeadlyAttack) {
|
||||
this.isDeadlyAttack = isDeadlyAttack;
|
||||
}
|
||||
|
||||
public boolean isDeadlyAttack() {
|
||||
return isDeadlyAttack;
|
||||
}
|
||||
|
||||
public void setMpBurn(int mpBurn) {
|
||||
this.mpBurn = mpBurn;
|
||||
}
|
||||
|
||||
public int getMpBurn() {
|
||||
return mpBurn;
|
||||
}
|
||||
|
||||
public void setDiseaseSkill(int diseaseSkill) {
|
||||
this.diseaseSkill = diseaseSkill;
|
||||
}
|
||||
|
||||
public int getDiseaseSkill() {
|
||||
return diseaseSkill;
|
||||
}
|
||||
|
||||
public void setDiseaseLevel(int diseaseLevel) {
|
||||
this.diseaseLevel = diseaseLevel;
|
||||
}
|
||||
|
||||
public int getDiseaseLevel() {
|
||||
return diseaseLevel;
|
||||
}
|
||||
|
||||
public void setMpCon(int mpCon) {
|
||||
this.mpCon = mpCon;
|
||||
}
|
||||
|
||||
public int getMpCon() {
|
||||
return mpCon;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
import provider.MapleDataTool;
|
||||
import tools.StringUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Danny (Leifde)
|
||||
*/
|
||||
public class MobAttackInfoFactory {
|
||||
private static Map<String, MobAttackInfo> mobAttacks = new HashMap<String, MobAttackInfo>();
|
||||
private static MapleDataProvider dataSource = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Mob.wz"));
|
||||
|
||||
public static MobAttackInfo getMobAttackInfo(MapleMonster mob, int attack) {
|
||||
MobAttackInfo ret = mobAttacks.get(mob.getId() + "" + attack);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
synchronized (mobAttacks) {
|
||||
ret = mobAttacks.get(mob.getId() + "" + attack);
|
||||
if (ret == null) {
|
||||
MapleData mobData = dataSource.getData(StringUtil.getLeftPaddedStr(Integer.toString(mob.getId()) + ".img", '0', 11));
|
||||
if (mobData != null) {
|
||||
// MapleData infoData = mobData.getChildByPath("info");
|
||||
String linkedmob = MapleDataTool.getString("link", mobData, "");
|
||||
if (!linkedmob.equals("")) {
|
||||
mobData = dataSource.getData(StringUtil.getLeftPaddedStr(linkedmob + ".img", '0', 11));
|
||||
}
|
||||
MapleData attackData = mobData.getChildByPath("attack" + (attack + 1) + "/info");
|
||||
|
||||
if (attackData == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MapleData deadlyAttack = attackData.getChildByPath("deadlyAttack");
|
||||
int mpBurn = MapleDataTool.getInt("mpBurn", attackData, 0);
|
||||
int disease = MapleDataTool.getInt("disease", attackData, 0);
|
||||
int level = MapleDataTool.getInt("level", attackData, 0);
|
||||
int mpCon = MapleDataTool.getInt("conMP", attackData, 0);
|
||||
ret = new MobAttackInfo(mob.getId(), attack);
|
||||
ret.setDeadlyAttack(deadlyAttack != null);
|
||||
ret.setMpBurn(mpBurn);
|
||||
ret.setDiseaseSkill(disease);
|
||||
ret.setDiseaseLevel(level);
|
||||
ret.setMpCon(mpCon);
|
||||
}
|
||||
mobAttacks.put(mob.getId() + "" + attack, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleDisease;
|
||||
import client.status.MonsterStatus;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import tools.Randomizer;
|
||||
import server.maps.MapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import server.maps.MapleMist;
|
||||
import tools.ArrayMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Danny (Leifde)
|
||||
*/
|
||||
public class MobSkill {
|
||||
private int skillId, skillLevel, mpCon;
|
||||
private List<Integer> toSummon = new ArrayList<Integer>();
|
||||
private int spawnEffect, hp, x, y;
|
||||
private long duration, cooltime;
|
||||
private float prop;
|
||||
private Point lt, rb;
|
||||
private int limit;
|
||||
|
||||
public MobSkill(int skillId, int level) {
|
||||
this.skillId = skillId;
|
||||
this.skillLevel = level;
|
||||
}
|
||||
|
||||
public void setMpCon(int mpCon) {
|
||||
this.mpCon = mpCon;
|
||||
}
|
||||
|
||||
public void addSummons(List<Integer> toSummon) {
|
||||
for (Integer summon : toSummon) {
|
||||
this.toSummon.add(summon);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSpawnEffect(int spawnEffect) {
|
||||
this.spawnEffect = spawnEffect;
|
||||
}
|
||||
|
||||
public void setHp(int hp) {
|
||||
this.hp = hp;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void setDuration(long duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public void setCoolTime(long cooltime) {
|
||||
this.cooltime = cooltime;
|
||||
}
|
||||
|
||||
public void setProp(float prop) {
|
||||
this.prop = prop;
|
||||
}
|
||||
|
||||
public void setLtRb(Point lt, Point rb) {
|
||||
this.lt = lt;
|
||||
this.rb = rb;
|
||||
}
|
||||
|
||||
public void setLimit(int limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public void applyEffect(MapleCharacter player, MapleMonster monster, boolean skill) {
|
||||
MapleDisease disease = null;
|
||||
Map<MonsterStatus, Integer> stats = new ArrayMap<MonsterStatus, Integer>();
|
||||
List<Integer> reflection = new LinkedList<Integer>();
|
||||
switch (skillId) {
|
||||
case 100:
|
||||
case 110:
|
||||
case 150:
|
||||
stats.put(MonsterStatus.WEAPON_ATTACK_UP, Integer.valueOf(x));
|
||||
break;
|
||||
case 101:
|
||||
case 111:
|
||||
case 151:
|
||||
stats.put(MonsterStatus.MAGIC_ATTACK_UP, Integer.valueOf(x));
|
||||
break;
|
||||
case 102:
|
||||
case 112:
|
||||
case 152:
|
||||
stats.put(MonsterStatus.WEAPON_DEFENSE_UP, Integer.valueOf(x));
|
||||
break;
|
||||
case 103:
|
||||
case 113:
|
||||
case 153:
|
||||
stats.put(MonsterStatus.MAGIC_DEFENSE_UP, Integer.valueOf(x));
|
||||
break;
|
||||
case 114:
|
||||
if (lt != null && rb != null && skill) {
|
||||
List<MapleMapObject> objects = getObjectsInRange(monster, MapleMapObjectType.MONSTER);
|
||||
final int hps = (getX() / 1000) * (int) (950 + 1050 * Math.random());
|
||||
for (MapleMapObject mons : objects) {
|
||||
((MapleMonster) mons).heal(hps, getY());
|
||||
}
|
||||
} else {
|
||||
monster.heal(getX(), getY());
|
||||
}
|
||||
break;
|
||||
case 120:
|
||||
disease = MapleDisease.SEAL;
|
||||
break;
|
||||
case 121:
|
||||
disease = MapleDisease.DARKNESS;
|
||||
break;
|
||||
case 122:
|
||||
disease = MapleDisease.WEAKEN;
|
||||
break;
|
||||
case 123:
|
||||
disease = MapleDisease.STUN;
|
||||
break;
|
||||
case 124:
|
||||
disease = MapleDisease.CURSE;
|
||||
break;
|
||||
case 125:
|
||||
disease = MapleDisease.POISON;
|
||||
break;
|
||||
case 126: // Slow
|
||||
disease = MapleDisease.SLOW;
|
||||
break;
|
||||
case 127:
|
||||
if (lt != null && rb != null && skill) {
|
||||
for (MapleCharacter character : getPlayersInRange(monster, player)) {
|
||||
character.dispel();
|
||||
}
|
||||
} else {
|
||||
player.dispel();
|
||||
}
|
||||
break;
|
||||
case 128: // Seduce
|
||||
disease = MapleDisease.SEDUCE;
|
||||
break;
|
||||
case 129: // Banish
|
||||
if (lt != null && rb != null && skill) {
|
||||
for (MapleCharacter chr : getPlayersInRange(monster, player)) {
|
||||
chr.changeMapBanish(monster.getBanish().getMap(), monster.getBanish().getPortal(), monster.getBanish().getMsg());
|
||||
}
|
||||
} else {
|
||||
player.changeMapBanish(monster.getBanish().getMap(), monster.getBanish().getPortal(), monster.getBanish().getMsg());
|
||||
}
|
||||
break;
|
||||
case 131: // Mist
|
||||
monster.getMap().spawnMist(new MapleMist(calculateBoundingBox(monster.getPosition(), true), monster, this), x * 10, false, false, false);
|
||||
break;
|
||||
case 132:
|
||||
disease = MapleDisease.CONFUSE;
|
||||
break;
|
||||
case 133: // zombify
|
||||
break;
|
||||
case 140:
|
||||
if (makeChanceResult() && !monster.isBuffed(MonsterStatus.MAGIC_IMMUNITY)) {
|
||||
stats.put(MonsterStatus.WEAPON_IMMUNITY, Integer.valueOf(x));
|
||||
}
|
||||
break;
|
||||
case 141:
|
||||
if (makeChanceResult() && !monster.isBuffed(MonsterStatus.WEAPON_IMMUNITY)) {
|
||||
stats.put(MonsterStatus.MAGIC_IMMUNITY, Integer.valueOf(x));
|
||||
}
|
||||
break;
|
||||
case 143: // Weapon Reflect
|
||||
stats.put(MonsterStatus.WEAPON_REFLECT, Integer.valueOf(x));
|
||||
stats.put(MonsterStatus.WEAPON_IMMUNITY, Integer.valueOf(x));
|
||||
reflection.add(x);
|
||||
break;
|
||||
case 144: // Magic Reflect
|
||||
stats.put(MonsterStatus.MAGIC_REFLECT, Integer.valueOf(x));
|
||||
stats.put(MonsterStatus.MAGIC_IMMUNITY, Integer.valueOf(x));
|
||||
reflection.add(x);
|
||||
break;
|
||||
case 145: // Weapon / Magic reflect
|
||||
stats.put(MonsterStatus.WEAPON_REFLECT, Integer.valueOf(x));
|
||||
stats.put(MonsterStatus.WEAPON_IMMUNITY, Integer.valueOf(x));
|
||||
stats.put(MonsterStatus.MAGIC_REFLECT, Integer.valueOf(x));
|
||||
stats.put(MonsterStatus.MAGIC_IMMUNITY, Integer.valueOf(x));
|
||||
reflection.add(x);
|
||||
break;
|
||||
case 154: // accuracy up
|
||||
case 155: // avoid up
|
||||
case 156: // speed up
|
||||
break;
|
||||
case 200:
|
||||
if (monster.getMap().getSpawnedMonstersOnMap() < 80) {
|
||||
for (Integer mobId : getSummons()) {
|
||||
MapleMonster toSpawn = MapleLifeFactory.getMonster(mobId);
|
||||
toSpawn.setPosition(monster.getPosition());
|
||||
int ypos, xpos;
|
||||
xpos = (int) monster.getPosition().getX();
|
||||
ypos = (int) monster.getPosition().getY();
|
||||
switch (mobId) {
|
||||
case 8500003: // Pap bomb high
|
||||
toSpawn.setFh((int) Math.ceil(Math.random() * 19.0));
|
||||
ypos = -590;
|
||||
break;
|
||||
case 8500004: // Pap bomb
|
||||
xpos = (int) (monster.getPosition().getX() + Randomizer.nextInt(1000) - 500);
|
||||
if (ypos != -590) {
|
||||
ypos = (int) monster.getPosition().getY();
|
||||
}
|
||||
break;
|
||||
case 8510100: //Pianus bomb
|
||||
if (Math.ceil(Math.random() * 5) == 1) {
|
||||
ypos = 78;
|
||||
xpos = (int) Randomizer.nextInt(5) + (Randomizer.nextInt(2) == 1 ? 180 : 0);
|
||||
} else {
|
||||
xpos = (int) (monster.getPosition().getX() + Randomizer.nextInt(1000) - 500);
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (monster.getMap().getId()) {
|
||||
case 220080001: //Pap map
|
||||
if (xpos < -890) {
|
||||
xpos = (int) (Math.ceil(Math.random() * 150) - 890);
|
||||
} else if (xpos > 230) {
|
||||
xpos = (int) (230 - Math.ceil(Math.random() * 150));
|
||||
}
|
||||
break;
|
||||
case 230040420: // Pianus map
|
||||
if (xpos < -239) {
|
||||
xpos = (int) (Math.ceil(Math.random() * 150) - 239);
|
||||
} else if (xpos > 371) {
|
||||
xpos = (int) (371 - Math.ceil(Math.random() * 150));
|
||||
}
|
||||
break;
|
||||
}
|
||||
toSpawn.setPosition(new Point(xpos, ypos));
|
||||
if (toSpawn.getId() == 8500004) {
|
||||
monster.getMap().spawnFakeMonster(toSpawn);
|
||||
} else {
|
||||
monster.getMap().spawnMonsterWithEffect(toSpawn, getSpawnEffect(), toSpawn.getPosition());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unhandeled Mob skill: " + skillId);
|
||||
break;
|
||||
}
|
||||
if (stats.size() > 0) {
|
||||
if (lt != null && rb != null && skill) {
|
||||
for (MapleMapObject mons : getObjectsInRange(monster, MapleMapObjectType.MONSTER)) {
|
||||
((MapleMonster) mons).applyMonsterBuff(stats, getX(), getSkillId(), getDuration(), this, reflection);
|
||||
}
|
||||
} else {
|
||||
monster.applyMonsterBuff(stats, getX(), getSkillId(), getDuration(), this, reflection);
|
||||
}
|
||||
}
|
||||
if (disease != null) {
|
||||
if (lt != null && rb != null && skill) {
|
||||
int i = 0;
|
||||
for (MapleCharacter character : getPlayersInRange(monster, player)) {
|
||||
if (!character.isActiveBuffedValue(2321005)) {
|
||||
if (disease.equals(MapleDisease.SEDUCE)) {
|
||||
if (i < 10) {
|
||||
character.giveDebuff(MapleDisease.SEDUCE, this);
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
character.giveDebuff(disease, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
player.giveDebuff(disease, this);
|
||||
}
|
||||
}
|
||||
monster.usedSkill(skillId, skillLevel, cooltime);
|
||||
monster.setMp(monster.getMp() - getMpCon());
|
||||
}
|
||||
|
||||
private List<MapleCharacter> getPlayersInRange(MapleMonster monster, MapleCharacter player) {
|
||||
List<MapleCharacter> players = new ArrayList<MapleCharacter>();
|
||||
players.add(player);
|
||||
return monster.getMap().getPlayersInRange(calculateBoundingBox(monster.getPosition(), monster.isFacingLeft()), players);
|
||||
}
|
||||
|
||||
public int getSkillId() {
|
||||
return skillId;
|
||||
}
|
||||
|
||||
public int getSkillLevel() {
|
||||
return skillLevel;
|
||||
}
|
||||
|
||||
public int getMpCon() {
|
||||
return mpCon;
|
||||
}
|
||||
|
||||
public List<Integer> getSummons() {
|
||||
return Collections.unmodifiableList(toSummon);
|
||||
}
|
||||
|
||||
public int getSpawnEffect() {
|
||||
return spawnEffect;
|
||||
}
|
||||
|
||||
public int getHP() {
|
||||
return hp;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public long getCoolTime() {
|
||||
return cooltime;
|
||||
}
|
||||
|
||||
public Point getLt() {
|
||||
return lt;
|
||||
}
|
||||
|
||||
public Point getRb() {
|
||||
return rb;
|
||||
}
|
||||
|
||||
public int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
public boolean makeChanceResult() {
|
||||
return prop == 1.0 || Math.random() < prop;
|
||||
}
|
||||
|
||||
private Rectangle calculateBoundingBox(Point posFrom, boolean facingLeft) {
|
||||
int multiplier = facingLeft ? 1 : -1;
|
||||
Point mylt = new Point(lt.x * multiplier + posFrom.x, lt.y + posFrom.y);
|
||||
Point myrb = new Point(rb.x * multiplier + posFrom.x, rb.y + posFrom.y);
|
||||
return new Rectangle(mylt.x, mylt.y, myrb.x - mylt.x, myrb.y - mylt.y);
|
||||
}
|
||||
|
||||
private List<MapleMapObject> getObjectsInRange(MapleMonster monster, MapleMapObjectType objectType) {
|
||||
List<MapleMapObjectType> objectTypes = new ArrayList<MapleMapObjectType>();
|
||||
objectTypes.add(objectType);
|
||||
return monster.getMap().getMapObjectsInBox(calculateBoundingBox(monster.getPosition(), monster.isFacingLeft()), objectTypes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
import provider.MapleDataTool;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Danny (Leifde)
|
||||
*/
|
||||
public class MobSkillFactory {
|
||||
|
||||
private static Map<String, MobSkill> mobSkills = new HashMap<String, MobSkill>();
|
||||
private final static MapleDataProvider dataSource = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Skill.wz"));
|
||||
private static MapleData skillRoot = dataSource.getData("MobSkill.img");
|
||||
private static ReentrantReadWriteLock dataLock = new ReentrantReadWriteLock();
|
||||
|
||||
public static MobSkill getMobSkill(final int skillId, final int level) {
|
||||
final String key = skillId + "" + level;
|
||||
dataLock.readLock().lock();
|
||||
try {
|
||||
MobSkill ret = mobSkills.get(key);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
} finally {
|
||||
dataLock.readLock().unlock();
|
||||
}
|
||||
dataLock.writeLock().lock();
|
||||
try {
|
||||
MobSkill ret;
|
||||
ret = mobSkills.get(key);
|
||||
if (ret == null) {
|
||||
MapleData skillData = skillRoot.getChildByPath(skillId + "/level/" + level);
|
||||
if (skillData != null) {
|
||||
int mpCon = MapleDataTool.getInt(skillData.getChildByPath("mpCon"), 0);
|
||||
List<Integer> toSummon = new ArrayList<Integer>();
|
||||
for (int i = 0; i > -1; i++) {
|
||||
if (skillData.getChildByPath(String.valueOf(i)) == null) {
|
||||
break;
|
||||
}
|
||||
toSummon.add(Integer.valueOf(MapleDataTool.getInt(skillData.getChildByPath(String.valueOf(i)), 0)));
|
||||
}
|
||||
int effect = MapleDataTool.getInt("summonEffect", skillData, 0);
|
||||
int hp = MapleDataTool.getInt("hp", skillData, 100);
|
||||
int x = MapleDataTool.getInt("x", skillData, 1);
|
||||
int y = MapleDataTool.getInt("y", skillData, 1);
|
||||
long duration = MapleDataTool.getInt("time", skillData, 0) * 1000;
|
||||
long cooltime = MapleDataTool.getInt("interval", skillData, 0) * 1000;
|
||||
int iprop = MapleDataTool.getInt("prop", skillData, 100);
|
||||
float prop = iprop / 100;
|
||||
int limit = MapleDataTool.getInt("limit", skillData, 0);
|
||||
MapleData ltd = skillData.getChildByPath("lt");
|
||||
Point lt = null;
|
||||
Point rb = null;
|
||||
if (ltd != null) {
|
||||
lt = (Point) ltd.getData();
|
||||
rb = (Point) skillData.getChildByPath("rb").getData();
|
||||
}
|
||||
ret = new MobSkill(skillId, level);
|
||||
ret.addSummons(toSummon);
|
||||
ret.setCoolTime(cooltime);
|
||||
ret.setDuration(duration);
|
||||
ret.setHp(hp);
|
||||
ret.setMpCon(mpCon);
|
||||
ret.setSpawnEffect(effect);
|
||||
ret.setX(x);
|
||||
ret.setY(y);
|
||||
ret.setProp(prop);
|
||||
ret.setLimit(limit);
|
||||
ret.setLtRb(lt, rb);
|
||||
}
|
||||
mobSkills.put(skillId + "" + level, ret);
|
||||
}
|
||||
return ret;
|
||||
} finally {
|
||||
dataLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 ~ 2010 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
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 server.life;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LightPepsi
|
||||
*/
|
||||
|
||||
public class MonsterDropEntry {
|
||||
public MonsterDropEntry(int itemId, int chance, int Minimum, int Maximum, short questid) {
|
||||
this.itemId = itemId;
|
||||
this.chance = chance;
|
||||
this.questid = questid;
|
||||
this.Minimum = Minimum;
|
||||
this.Maximum = Maximum;
|
||||
}
|
||||
public short questid;
|
||||
public int itemId, chance, Minimum, Maximum;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 ~ 2010 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
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 server.life;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LightPepsi
|
||||
*/
|
||||
public class MonsterGlobalDropEntry {
|
||||
public MonsterGlobalDropEntry(int itemId, int chance, int continent, byte dropType, int Minimum, int Maximum, short questid) {
|
||||
this.itemId = itemId;
|
||||
this.chance = chance;
|
||||
this.dropType = dropType;
|
||||
this.questid = questid;
|
||||
this.Minimum = Minimum;
|
||||
this.Maximum = Maximum;
|
||||
}
|
||||
public byte dropType;
|
||||
public int itemId, chance, Minimum, Maximum;
|
||||
public short questid;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package server.life;
|
||||
|
||||
public interface MonsterListener {
|
||||
|
||||
public void monsterKilled(int aniTime);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <[email protected]>
|
||||
Matthias Butz <[email protected]>
|
||||
Jan Christian Meyer <[email protected]>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation 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 server.life;
|
||||
|
||||
import client.MapleCharacter;
|
||||
import java.awt.Point;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class SpawnPoint {
|
||||
|
||||
private int monster, mobTime, team, fh, f;
|
||||
private Point pos;
|
||||
private long nextPossibleSpawn;
|
||||
private int mobInterval = 5000;
|
||||
private AtomicInteger spawnedMonsters = new AtomicInteger(0);
|
||||
private boolean immobile;
|
||||
|
||||
public SpawnPoint(final MapleMonster monster, Point pos, boolean immobile, int mobTime, int mobInterval, int team) {
|
||||
this.monster = monster.getId();
|
||||
this.pos = new Point(pos);
|
||||
this.mobTime = mobTime;
|
||||
this.team = team;
|
||||
this.fh = monster.getFh();
|
||||
this.f = monster.getF();
|
||||
this.immobile = immobile;
|
||||
this.mobInterval = mobInterval;
|
||||
this.nextPossibleSpawn = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean shouldSpawn() {
|
||||
if (mobTime < 0 || ((mobTime != 0 || immobile) && spawnedMonsters.get() > 0) || spawnedMonsters.get() > 2) {//lol
|
||||
return false;
|
||||
}
|
||||
|
||||
return nextPossibleSpawn <= System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean shouldForceSpawn() {
|
||||
if (mobTime < 0 || ((mobTime != 0 || immobile) && spawnedMonsters.get() > 0) || spawnedMonsters.get() > 2) {//lol
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public MapleMonster getMonster() {
|
||||
MapleMonster mob = new MapleMonster(MapleLifeFactory.getMonster(monster));
|
||||
mob.setPosition(new Point(pos));
|
||||
mob.setTeam(team);
|
||||
mob.setFh(fh);
|
||||
mob.setF(f);
|
||||
spawnedMonsters.incrementAndGet();
|
||||
mob.addListener(new MonsterListener() {
|
||||
@Override
|
||||
public void monsterKilled(int aniTime) {
|
||||
nextPossibleSpawn = System.currentTimeMillis();
|
||||
if (mobTime > 0) {
|
||||
nextPossibleSpawn += mobTime * 1000;
|
||||
} else {
|
||||
nextPossibleSpawn += aniTime;
|
||||
}
|
||||
spawnedMonsters.decrementAndGet();
|
||||
}
|
||||
});
|
||||
if (mobTime == 0) {
|
||||
nextPossibleSpawn = System.currentTimeMillis() + mobInterval;
|
||||
}
|
||||
return mob;
|
||||
}
|
||||
|
||||
public Point getPosition() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public final int getF() {
|
||||
return f;
|
||||
}
|
||||
|
||||
public final int getFh() {
|
||||
return fh;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user