Fixed an inconsistent scenario where player data would remain in world player storage even though they were no longer online. Implemented missing functionality for "Safety Charm" which allows 30% MaxHP/MP heal on return. Improved services facility, no longer tightly related to channels. Implemented a world service for "save players" (services acts as a monitor). Reviewed the event script initialization approach. Players no longer are retained from logging in on a channel whilst the events don't finish loadup. Fixed certain quest items not showing up, which would happen due to them not being quest requisites. Fixed NPC Pi crashing players when trying to craft arrows. Fixed pet re-evolution quest not working on Robos. Fixed boss HPBar not disappearing in certain situations. Revised gathered mob info on linked mobs, no longer marshaling stats. Fixed two possible deadlock scenarios within the cancel effect method. Added lock auditing support for read-write locks. Implemented code support for Cygnus intro clip. Reviewed updateBuffEffect, now properly checking for pirate buffs in order to send the expected packet. Reviewed unnecessary load of field objects, which would be doing so just for fetching the predicted map names. Fixed mob buff tooltips not showing on "fake" mobs in the event of them turning into "real". Reviewed usage of "unique" constraint on petid within the inventoryitems table. Fixed portal in Ariant unexpectedly leading players who completed the "secret passageway" of Sleepywood into it. Fixed a loop case in quest scripts from Magatia's broker having ore request.
223 lines
7.1 KiB
Java
223 lines
7.1 KiB
Java
/*
|
|
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.maps;
|
|
|
|
import java.awt.Point;
|
|
import java.util.Collections;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
*
|
|
* @author Matze
|
|
*/
|
|
public class MapleFootholdTree {
|
|
private MapleFootholdTree nw = null;
|
|
private MapleFootholdTree ne = null;
|
|
private MapleFootholdTree sw = null;
|
|
private MapleFootholdTree se = null;
|
|
private List<MapleFoothold> footholds = new LinkedList<MapleFoothold>();
|
|
private Point p1;
|
|
private Point p2;
|
|
private Point center;
|
|
private int depth = 0;
|
|
private static int maxDepth = 8;
|
|
private int maxDropX;
|
|
private int minDropX;
|
|
|
|
public MapleFootholdTree(Point p1, Point p2) {
|
|
this.p1 = p1;
|
|
this.p2 = p2;
|
|
center = new Point((p2.x - p1.x) / 2, (p2.y - p1.y) / 2);
|
|
}
|
|
|
|
public MapleFootholdTree(Point p1, Point p2, int depth) {
|
|
this.p1 = p1;
|
|
this.p2 = p2;
|
|
this.depth = depth;
|
|
center = new Point((p2.x - p1.x) / 2, (p2.y - p1.y) / 2);
|
|
}
|
|
|
|
public void insert(MapleFoothold f) {
|
|
if (depth == 0) {
|
|
if (f.getX1() > maxDropX) {
|
|
maxDropX = f.getX1();
|
|
}
|
|
if (f.getX1() < minDropX) {
|
|
minDropX = f.getX1();
|
|
}
|
|
if (f.getX2() > maxDropX) {
|
|
maxDropX = f.getX2();
|
|
}
|
|
if (f.getX2() < minDropX) {
|
|
minDropX = f.getX2();
|
|
}
|
|
}
|
|
if (depth == maxDepth ||
|
|
(f.getX1() >= p1.x && f.getX2() <= p2.x &&
|
|
f.getY1() >= p1.y && f.getY2() <= p2.y)) {
|
|
footholds.add(f);
|
|
} else {
|
|
if (nw == null) {
|
|
nw = new MapleFootholdTree(p1, center, depth + 1);
|
|
ne = new MapleFootholdTree(new Point(center.x, p1.y), new Point(p2.x, center.y), depth + 1);
|
|
sw = new MapleFootholdTree(new Point(p1.x, center.y), new Point(center.x, p2.y), depth + 1);
|
|
se = new MapleFootholdTree(center, p2, depth + 1);
|
|
}
|
|
if (f.getX2() <= center.x && f.getY2() <= center.y) {
|
|
nw.insert(f);
|
|
} else if (f.getX1() > center.x && f.getY2() <= center.y) {
|
|
ne.insert(f);
|
|
} else if (f.getX2() <= center.x && f.getY1() > center.y) {
|
|
sw.insert(f);
|
|
} else {
|
|
se.insert(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
private List<MapleFoothold> getRelevants(Point p) {
|
|
return getRelevants(p, new LinkedList<MapleFoothold>());
|
|
}
|
|
|
|
private List<MapleFoothold> getRelevants(Point p, List<MapleFoothold> list) {
|
|
list.addAll(footholds);
|
|
if (nw != null) {
|
|
if (p.x <= center.x && p.y <= center.y) {
|
|
nw.getRelevants(p, list);
|
|
} else if (p.x > center.x && p.y <= center.y) {
|
|
ne.getRelevants(p, list);
|
|
} else if (p.x <= center.x && p.y > center.y) {
|
|
sw.getRelevants(p, list);
|
|
} else {
|
|
se.getRelevants(p, list);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private MapleFoothold findWallR(Point p1, Point p2) {
|
|
MapleFoothold ret;
|
|
for (MapleFoothold f : footholds) {
|
|
if (f.isWall() && f.getX1() >= p1.x && f.getX1() <= p2.x &&
|
|
f.getY1() >= p1.y && f.getY2() <= p1.y) {
|
|
return f;
|
|
}
|
|
}
|
|
if (nw != null) {
|
|
if (p1.x <= center.x && p1.y <= center.y) {
|
|
ret = nw.findWallR(p1, p2);
|
|
if (ret != null) {
|
|
return ret;
|
|
}
|
|
}
|
|
if ((p1.x > center.x || p2.x > center.x) && p1.y <= center.y) {
|
|
ret = ne.findWallR(p1, p2);
|
|
if (ret != null) {
|
|
return ret;
|
|
}
|
|
}
|
|
if (p1.x <= center.x && p1.y > center.y) {
|
|
ret = sw.findWallR(p1, p2);
|
|
if (ret != null) {
|
|
return ret;
|
|
}
|
|
}
|
|
if ((p1.x > center.x || p2.x > center.x) && p1.y > center.y) {
|
|
ret = se.findWallR(p1, p2);
|
|
if (ret != null) {
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public MapleFoothold findWall(Point p1, Point p2) {
|
|
if (p1.y != p2.y) {
|
|
throw new IllegalArgumentException();
|
|
}
|
|
return findWallR(p1, p2);
|
|
}
|
|
|
|
public MapleFoothold findBelow(Point p) {
|
|
List<MapleFoothold> relevants = getRelevants(p);
|
|
List<MapleFoothold> xMatches = new LinkedList<MapleFoothold>();
|
|
for (MapleFoothold fh : relevants) {
|
|
if (fh.getX1() <= p.x && fh.getX2() >= p.x) {
|
|
xMatches.add(fh);
|
|
}
|
|
}
|
|
Collections.sort(xMatches);
|
|
for (MapleFoothold fh : xMatches) {
|
|
if (!fh.isWall()) {
|
|
if (fh.getY1() != fh.getY2()) {
|
|
int calcY;
|
|
double s1 = Math.abs(fh.getY2() - fh.getY1());
|
|
double s2 = Math.abs(fh.getX2() - fh.getX1());
|
|
double s4 = Math.abs(p.x - fh.getX1());
|
|
double alpha = Math.atan(s2 / s1);
|
|
double beta = Math.atan(s1 / s2);
|
|
double s5 = Math.cos(alpha) * (s4 / Math.cos(beta));
|
|
if (fh.getY2() < fh.getY1()) {
|
|
calcY = fh.getY1() - (int) s5;
|
|
} else {
|
|
calcY = fh.getY1() + (int) s5;
|
|
}
|
|
if (calcY >= p.y) {
|
|
return fh;
|
|
}
|
|
} else {
|
|
if (fh.getY1() >= p.y) {
|
|
return fh;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public int getX1() {
|
|
return p1.x;
|
|
}
|
|
|
|
public int getX2() {
|
|
return p2.x;
|
|
}
|
|
|
|
public int getY1() {
|
|
return p1.y;
|
|
}
|
|
|
|
public int getY2() {
|
|
return p2.y;
|
|
}
|
|
|
|
public int getMaxDropX() {
|
|
return maxDropX;
|
|
}
|
|
|
|
public int getMinDropX() {
|
|
return minDropX;
|
|
}
|
|
}
|