/*
OrpheusMS: MapleStory Private Server based on OdinMS
Copyright (C) 2012 Aaron Weiss <aaron@deviant-core.net>
Patrick Huy <patrick.huy@frz.cc>
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
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.maps;
import java.awt.Rectangle;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import provider.MapleData;
import provider.MapleDataProvider;
import provider.MapleDataTool;
import server.PortalFactory;
import server.life.AbstractLoadedMapleLife;
import server.life.MapleLifeFactory;
import server.life.MapleMonster;
import tools.StringUtil;
import java.awt.Point;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import tools.DatabaseConnection;
public class MapleMapFactory {
private MapleDataProvider source;
private MapleData nameData;
private Map<Integer, MapleMap> maps = new HashMap<Integer, MapleMap>();
private byte channel, world;
public MapleMapFactory(MapleDataProvider source, MapleDataProvider stringSource, byte world, byte channel) {
this.source = source;
this.nameData = stringSource.getData("Map.img");
this.world = world;
this.channel = channel;
}
public MapleMap getMap(int mapid) {
Integer omapid = Integer.valueOf(mapid);
MapleMap map = maps.get(omapid);
if (map == null) {
synchronized (this) {
map = maps.get(omapid);
if (map != null) {
return map;
}
String mapName = getMapName(mapid);
MapleData mapData = source.getData(mapName);
String link = MapleDataTool.getString(mapData.getChildByPath("info/link"), "");
if (!link.equals("")) { // nexon made hundreds of dojo maps so
// to reduce the size they added links.
mapName = getMapName(Integer.parseInt(link));
mapData = source.getData(mapName);
}
float monsterRate = 0;
MapleData mobRate = mapData.getChildByPath("info/mobRate");
if (mobRate != null) {
monsterRate = ((Float) mobRate.getData()).floatValue();
}
map = new MapleMap(mapid, world, channel, MapleDataTool.getInt("info/returnMap", mapData), monsterRate);
map.setOnFirstUserEnter(MapleDataTool.getString(mapData.getChildByPath("info/onFirstUserEnter"), String.valueOf(mapid)));
map.setOnUserEnter(MapleDataTool.getString(mapData.getChildByPath("info/onUserEnter"), String.valueOf(mapid)));
map.setFieldLimit(MapleDataTool.getInt(mapData.getChildByPath("info/fieldLimit"), 0));
map.setMobInterval((short) MapleDataTool.getInt(mapData.getChildByPath("info/createMobInterval"), 5000));
PortalFactory portalFactory = new PortalFactory();
for (MapleData portal : mapData.getChildByPath("portal")) {
map.addPortal(portalFactory.makePortal(MapleDataTool.getInt(portal.getChildByPath("pt")), portal));
}
MapleData timeMob = mapData.getChildByPath("info/timeMob");
if (timeMob != null)
map.timeMob(MapleDataTool.getInt(timeMob.getChildByPath("id")), MapleDataTool.getString(timeMob.getChildByPath("message")));
List<MapleFoothold> allFootholds = new LinkedList<MapleFoothold>();
Point lBound = new Point();
Point uBound = new Point();
for (MapleData footRoot : mapData.getChildByPath("foothold")) {
for (MapleData footCat : footRoot) {
for (MapleData footHold : footCat) {
int x1 = MapleDataTool.getInt(footHold.getChildByPath("x1"));
int y1 = MapleDataTool.getInt(footHold.getChildByPath("y1"));
int x2 = MapleDataTool.getInt(footHold.getChildByPath("x2"));
int y2 = MapleDataTool.getInt(footHold.getChildByPath("y2"));
MapleFoothold fh = new MapleFoothold(new Point(x1, y1), new Point(x2, y2), Integer.parseInt(footHold.getName()));
fh.setPrev(MapleDataTool.getInt(footHold.getChildByPath("prev")));
fh.setNext(MapleDataTool.getInt(footHold.getChildByPath("next")));
if (fh.getX1() < lBound.x) {
lBound.x = fh.getX1();
}
if (fh.getX2() > uBound.x) {
uBound.x = fh.getX2();
}
if (fh.getY1() < lBound.y) {
lBound.y = fh.getY1();
}
if (fh.getY2() > uBound.y) {
uBound.y = fh.getY2();
}
allFootholds.add(fh);
}
}
}
MapleFootholdTree fTree = new MapleFootholdTree(lBound, uBound);
for (MapleFoothold fh : allFootholds) {
fTree.insert(fh);
}
map.setFootholds(fTree);
if (mapData.getChildByPath("area") != null) {
for (MapleData area : mapData.getChildByPath("area")) {
int x1 = MapleDataTool.getInt(area.getChildByPath("x1"));
int y1 = MapleDataTool.getInt(area.getChildByPath("y1"));
int x2 = MapleDataTool.getInt(area.getChildByPath("x2"));
int y2 = MapleDataTool.getInt(area.getChildByPath("y2"));
map.addMapleArea(new Rectangle(x1, y1, (x2 - x1), (y2 - y1)));
}
}
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM spawns WHERE mid = ?");
ps.setInt(1, omapid);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt("idd");
int f = rs.getInt("f");
boolean hide = false;
String type = rs.getString("type");
int fh = rs.getInt("fh");
int cy = rs.getInt("cy");
int rx0 = rs.getInt("rx0");
int rx1 = rs.getInt("rx1");
int x = rs.getInt("x");
int y = rs.getInt("y");
int mobTime = rs.getInt("mobtime");
AbstractLoadedMapleLife myLife = giveLife(id, f, hide, fh, cy, rx0, rx1, x, y, type);
if (type.equals("n")) {
map.addMapObject(myLife);
} else if (type.equals("m")) {
MapleMonster monster = (MapleMonster) myLife;
map.addMonsterSpawn(monster, mobTime, 0);
}
}
} catch (Exception e) {
}
try { // TODO, make better, perhaps for few maps only OKIDOKI!
PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("SELECT * FROM playernpcs WHERE map = ?");
ps.setInt(1, omapid);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
map.addMapObject(new PlayerNPCs(rs));
}
rs.close();
ps.close();
} catch (Exception e) {
}
for (MapleData life : mapData.getChildByPath("life")) {
String id = MapleDataTool.getString(life.getChildByPath("id"));
String type = MapleDataTool.getString(life.getChildByPath("type"));
if (id.equals("9001105"))
id = "9001108";// soz
AbstractLoadedMapleLife myLife = loadLife(life, id, type);
if (myLife instanceof MapleMonster) {
MapleMonster monster = (MapleMonster) myLife;
int mobTime = MapleDataTool.getInt("mobTime", life, 0);
int team = MapleDataTool.getInt("team", life, -1);
if (mobTime == -1) { // does not respawn, force spawn
// once
map.spawnMonster(monster);
} else {
map.addMonsterSpawn(monster, mobTime, team);
}
} else {
map.addMapObject(myLife);
}
}
if (mapData.getChildByPath("reactor") != null) {
for (MapleData reactor : mapData.getChildByPath("reactor")) {
String id = MapleDataTool.getString(reactor.getChildByPath("id"));
if (id != null) {
MapleReactor newReactor = loadReactor(reactor, id);
map.spawnReactor(newReactor);
}
}
}
try {
map.setMapName(MapleDataTool.getString("mapName", nameData.getChildByPath(getMapStringName(omapid)), ""));
map.setStreetName(MapleDataTool.getString("streetName", nameData.getChildByPath(getMapStringName(omapid)), ""));
} catch (Exception e) {
map.setMapName("");
map.setStreetName("");
}
map.setClock(mapData.getChildByPath("clock") != null);
map.setEverlast(mapData.getChildByPath("everlast") != null);
map.setTown(mapData.getChildByPath("town") != null);
map.setHPDec(MapleDataTool.getIntConvert("decHP", mapData, 0));
map.setHPDecProtect(MapleDataTool.getIntConvert("protectItem", mapData, 0));
map.setForcedReturnMap(MapleDataTool.getInt(mapData.getChildByPath("info/forcedReturn"), 999999999));
map.setBoat(mapData.getChildByPath("shipObj") != null);
map.setTimeLimit(MapleDataTool.getIntConvert("timeLimit", mapData.getChildByPath("info"), -1));
map.setFieldType(MapleDataTool.getIntConvert("info/fieldType", mapData, 0));
map.setMobCapacity(MapleDataTool.getIntConvert("fixedMobCapacity", mapData.getChildByPath("info"), 500));// Is
// there
// a
// map
// that
// contains
// more
// than
// 500
// mobs?
maps.put(omapid, map);
}
}
return map;
}
public boolean isMapLoaded(int mapId) {
return maps.containsKey(mapId);
}
private AbstractLoadedMapleLife giveLife(int id, int f, boolean hide, int fh, int cy, int rx0, int rx1, int x, int y, String type) {
AbstractLoadedMapleLife myLife = MapleLifeFactory.getLife(id, type);
myLife.setCy(cy);
myLife.setF(f);
myLife.setFh(fh);
myLife.setRx0(rx0);
myLife.setRx1(rx1);
myLife.setPosition(new Point(x, y));
myLife.setHide(hide);
return myLife;
}
private AbstractLoadedMapleLife loadLife(MapleData life, String id, String type) {
AbstractLoadedMapleLife myLife = MapleLifeFactory.getLife(Integer.parseInt(id), type);
myLife.setCy(MapleDataTool.getInt(life.getChildByPath("cy")));
MapleData dF = life.getChildByPath("f");
if (dF != null) {
myLife.setF(MapleDataTool.getInt(dF));
}
myLife.setFh(MapleDataTool.getInt(life.getChildByPath("fh")));
myLife.setRx0(MapleDataTool.getInt(life.getChildByPath("rx0")));
myLife.setRx1(MapleDataTool.getInt(life.getChildByPath("rx1")));
int x = MapleDataTool.getInt(life.getChildByPath("x"));
int y = MapleDataTool.getInt(life.getChildByPath("y"));
myLife.setPosition(new Point(x, y));
int hide = MapleDataTool.getInt("hide", life, 0);
if (hide == 1) {
myLife.setHide(true);
}
return myLife;
}
private MapleReactor loadReactor(MapleData reactor, String id) {
MapleReactor myReactor = new MapleReactor(MapleReactorFactory.getReactor(Integer.parseInt(id)), Integer.parseInt(id));
int x = MapleDataTool.getInt(reactor.getChildByPath("x"));
int y = MapleDataTool.getInt(reactor.getChildByPath("y"));
myReactor.setPosition(new Point(x, y));
myReactor.setDelay(MapleDataTool.getInt(reactor.getChildByPath("reactorTime")) * 1000);
myReactor.setState((byte) 0);
myReactor.setName(MapleDataTool.getString(reactor.getChildByPath("name"), ""));
return myReactor;
}
private String getMapName(int mapid) {
String mapName = StringUtil.getLeftPaddedStr(Integer.toString(mapid), '0', 9);
StringBuilder builder = new StringBuilder("Map/Map");
int area = mapid / 100000000;
builder.append(area);
builder.append("/");
builder.append(mapName);
builder.append(".img");
mapName = builder.toString();
return mapName;
}
private String getMapStringName(int mapid) {
StringBuilder builder = new StringBuilder();
if (mapid < 100000000) {
builder.append("maple");
} else if (mapid >= 100000000 && mapid < 200000000) {
builder.append("victoria");
} else if (mapid >= 200000000 && mapid < 300000000) {
builder.append("ossyria");
} else if (mapid >= 540000000 && mapid < 541010110) {
builder.append("singapore");
} else if (mapid >= 600000000 && mapid < 620000000) {
builder.append("MasteriaGL");
} else if (mapid >= 670000000 && mapid < 682000000) {
builder.append("weddingGL");
} else if (mapid >= 682000000 && mapid < 683000000) {
builder.append("HalloweenGL");
} else if (mapid >= 800000000 && mapid < 900000000) {
builder.append("jp");
} else {
builder.append("etc");
}
builder.append("/").append(mapid);
return builder.toString();
}
public void setChannel(byte channel) {
this.channel = channel;
}
public void setWorld(byte world) {
this.channel = world;
}
public Map<Integer, MapleMap> getMaps() {
return maps;
}
}