Neo City + Revamped EllinPQ + New Release

Fixed Neo City area, now playable.
Overhauled the EllinPQ mechanics, such as the "CLEAR" effect when passing maps, and some bug fixes along the way.
Refactored a lot of out-of-place classes and properly renamed a few others through the project.
Updated readme and licenses through the source, preparing the stage for the new release.
This commit is contained in:
ronancpl
2017-11-29 00:57:50 -02:00
parent 46924812b0
commit 85a81b9bf9
163 changed files with 17125 additions and 14961 deletions
+2 -4
View File
@@ -1,8 +1,6 @@
/*
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 file is part of the HeavenMS (MapleSolaxiaV2) MapleStory Server
Copyleft (L) 2017 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
-1
View File
@@ -41,7 +41,6 @@ import tools.locks.MonitoredReentrantLock;
import net.server.Server;
import server.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
import server.MaplePlayerShopItem;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
import tools.Pair;
+56 -24
View File
@@ -262,9 +262,7 @@ public class MapleMap {
MapleReactor mr = (MapleReactor) o;
mr.lockReactor();
try {
mr.setState((byte) 1);
mr.resetReactorActions();
mr.resetReactorActions(1);
broadcastMessage(MaplePacketCreator.triggerReactor((MapleReactor) o, 1));
} finally {
mr.unlockReactor();
@@ -768,7 +766,7 @@ public class MapleMap {
}
private void spawnDrop(final Item idrop, final Point dropPos, final MapleMapObject dropper, final MapleCharacter chr, final byte droptype, final short questid) {
final MapleMapItem mdrop = new MapleMapItem(idrop, dropPos, dropper, chr, droptype, false, questid);
final MapleMapItem mdrop = new MapleMapItem(idrop, dropPos, dropper, chr, chr.getClient(), droptype, false, questid);
mdrop.setDropTime(System.currentTimeMillis());
spawnAndAddRangedMapObject(mdrop, new DelayedPacketCreation() {
@Override
@@ -785,7 +783,7 @@ public class MapleMap {
public final void spawnMesoDrop(final int meso, final Point position, final MapleMapObject dropper, final MapleCharacter owner, final boolean playerDrop, final byte droptype) {
final Point droppos = calcDropPos(position, position);
final MapleMapItem mdrop = new MapleMapItem(meso, droppos, dropper, owner, droptype, playerDrop);
final MapleMapItem mdrop = new MapleMapItem(meso, droppos, dropper, owner, owner.getClient(), droptype, playerDrop);
mdrop.setDropTime(System.currentTimeMillis());
spawnAndAddRangedMapObject(mdrop, new DelayedPacketCreation() {
@@ -800,7 +798,7 @@ public class MapleMap {
public final void disappearingItemDrop(final MapleMapObject dropper, final MapleCharacter owner, final Item item, final Point pos) {
final Point droppos = calcDropPos(pos, pos);
final MapleMapItem drop = new MapleMapItem(item, droppos, dropper, owner, (byte) 1, false);
final MapleMapItem drop = new MapleMapItem(item, droppos, dropper, owner, owner.getClient(), (byte) 1, false);
broadcastMessage(MaplePacketCreator.dropItemFromMapObject(drop, dropper.getPosition(), droppos, (byte) 3), drop.getPosition());
}
@@ -1024,7 +1022,7 @@ public class MapleMap {
spawnedMonstersOnMap.decrementAndGet();
monster.setHp(0);
removeMapObject(monster);
monster.dispatchMonsterKilled();
monster.dispatchMonsterKilled(false);
broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition());
return;
}
@@ -1104,7 +1102,7 @@ public class MapleMap {
}
}
monster.dispatchMonsterKilled();
monster.dispatchMonsterKilled(true);
broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition());
}
@@ -1202,26 +1200,29 @@ public class MapleMap {
}
public void resetReactors() {
List<MapleReactor> list = new ArrayList<>();
objectRLock.lock();
try {
for (MapleMapObject o : mapobjects.values()) {
if (o.getType() == MapleMapObjectType.REACTOR) {
final MapleReactor r = ((MapleReactor) o);
r.lockReactor();
try {
r.setState((byte) 0);
r.resetReactorActions();
broadcastMessage(MaplePacketCreator.triggerReactor(r, 0));
} finally {
r.unlockReactor();
}
list.add(r);
}
}
} finally {
objectRLock.unlock();
}
for (MapleReactor r : list) {
r.lockReactor();
try {
r.resetReactorActions(0);
broadcastMessage(MaplePacketCreator.triggerReactor(r, 0));
} finally {
r.unlockReactor();
}
}
}
public void shuffleReactors() {
@@ -1680,8 +1681,7 @@ public class MapleMap {
private void respawnReactor(final MapleReactor reactor) {
reactor.lockReactor();
try {
reactor.setState((byte) 0);
reactor.resetReactorActions();
reactor.resetReactorActions(0);
reactor.setAlive(true);
} finally {
reactor.unlockReactor();
@@ -1799,7 +1799,7 @@ public class MapleMap {
public final void spawnItemDrop(final MapleMapObject dropper, final MapleCharacter owner, final Item item, Point pos, final byte dropType, final boolean playerDrop) {
final Point droppos = calcDropPos(pos, pos);
final MapleMapItem mdrop = new MapleMapItem(item, droppos, dropper, owner, dropType, playerDrop);
final MapleMapItem mdrop = new MapleMapItem(item, droppos, dropper, owner, owner.getClient(), dropType, playerDrop);
mdrop.setDropTime(System.currentTimeMillis());
spawnAndAddRangedMapObject(mdrop, new DelayedPacketCreation() {
@@ -1874,6 +1874,39 @@ public class MapleMap {
}
}
public void searchItemReactors(final MapleReactor react) {
if (react.getReactorType() == 100) {
Pair<Integer, Integer> reactProp = react.getReactItem(react.getEventState());
int reactItem = reactProp.getLeft(), reactQty = reactProp.getRight();
Rectangle reactArea = react.getArea();
List<MapleMapItem> list = new ArrayList<>();
objectRLock.lock();
try {
for(MapleMapItem mmi : droppedItems.keySet()) {
if(!mmi.isPickedUp()) {
list.add(mmi);
}
}
} finally {
objectRLock.unlock();
}
for(final MapleMapItem drop : list) {
final Item item = drop.getItem();
if (reactItem == item.getItemId() && reactQty == item.getQuantity()) {
if (reactArea.contains(drop.getPosition())) {
MapleClient owner = drop.getOwnerClient();
if(owner != null) {
TimerManager.getInstance().schedule(new ActivateItemReactor(drop, react, owner), 5000);
}
}
}
}
}
}
public void changeEnvironment(String mapObj, int newState) {
broadcastMessage(MaplePacketCreator.environmentChange(mapObj, newState));
}
@@ -2808,6 +2841,7 @@ public class MapleMap {
if (mapitem.isPickedUp()) {
return;
}
mapitem.setPickedUp(true);
reactor.setShouldCollect(false);
MapleMap.this.broadcastMessage(MaplePacketCreator.removeItemFromMap(mapitem.getObjectId(), 0, 0), mapitem.getPosition());
@@ -2821,9 +2855,7 @@ public class MapleMap {
public void run() {
reactor.lockReactor();
try {
reactor.setState((byte) 0);
reactor.resetReactorActions();
reactor.resetReactorActions(0);
broadcastMessage(MaplePacketCreator.triggerReactor(reactor, 0));
} finally {
reactor.unlockReactor();
+1 -2
View File
@@ -340,9 +340,8 @@ public class MapleMapFactory {
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"), ""));
myReactor.resetReactorActions();
myReactor.resetReactorActions(0);
return myReactor;
}
+13 -6
View File
@@ -30,7 +30,7 @@ import tools.MaplePacketCreator;
import tools.locks.MonitoredLockType;
public class MapleMapItem extends AbstractMapleMapObject {
protected MapleClient ownerClient;
protected Item item;
protected MapleMapObject dropper;
protected int character_ownerid, meso, questid = -1;
@@ -39,33 +39,36 @@ public class MapleMapItem extends AbstractMapleMapObject {
protected long dropTime;
private Lock itemLock = new MonitoredReentrantLock(MonitoredLockType.MAP_ITEM);
public MapleMapItem(Item item, Point position, MapleMapObject dropper, MapleCharacter owner, byte type, boolean playerDrop) {
public MapleMapItem(Item item, Point position, MapleMapObject dropper, MapleCharacter owner, MapleClient ownerClient, byte type, boolean playerDrop) {
setPosition(position);
this.item = item;
this.dropper = dropper;
this.character_ownerid = owner.getId();
this.ownerClient = owner.getClient();
this.meso = 0;
this.type = type;
this.playerDrop = playerDrop;
}
public MapleMapItem(Item item, Point position, MapleMapObject dropper, MapleCharacter owner, byte type, boolean playerDrop, int questid) {
public MapleMapItem(Item item, Point position, MapleMapObject dropper, MapleCharacter owner, MapleClient ownerClient, byte type, boolean playerDrop, int questid) {
setPosition(position);
this.item = item;
this.dropper = dropper;
this.character_ownerid = owner.getParty() == null ? owner.getId() : owner.getPartyId();
this.meso = 0;
this.ownerClient = owner.getClient();
this.meso = 0;
this.type = type;
this.playerDrop = playerDrop;
this.questid = questid;
}
public MapleMapItem(int meso, Point position, MapleMapObject dropper, MapleCharacter owner, byte type, boolean playerDrop) {
public MapleMapItem(int meso, Point position, MapleMapObject dropper, MapleCharacter owner, MapleClient ownerClient, byte type, boolean playerDrop) {
setPosition(position);
this.item = null;
this.dropper = dropper;
this.character_ownerid = owner.getParty() == null ? owner.getId() : owner.getPartyId();
this.meso = meso;
this.ownerClient = owner.getClient();
this.meso = meso;
this.type = type;
this.playerDrop = playerDrop;
}
@@ -90,6 +93,10 @@ public class MapleMapItem extends AbstractMapleMapObject {
public final int getOwner() {
return character_ownerid;
}
public final MapleClient getOwnerClient() {
return (ownerClient.isLoggedIn() && !ownerClient.getPlayer().isAwayFromWorld()) ? ownerClient : null;
}
public final int getMeso() {
return meso;
+2 -1
View File
@@ -1,5 +1,6 @@
/*
This file is part of the MapleSolaxiaV2 Maple Story Server
This file is part of the HeavenMS (MapleSolaxiaV2) MapleStory Server
Copyleft (L) 2017 RonanLana
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
+339
View File
@@ -0,0 +1,339 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 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 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 client.MapleCharacter;
import client.MapleClient;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import tools.MaplePacketCreator;
/**
*
* @author Matze
*/
public class MapleMiniGame extends AbstractMapleMapObject {
private MapleCharacter owner;
private MapleCharacter visitor;
private String GameType = null;
private int[] piece = new int[250];
private List<Integer> list4x3 = new ArrayList<>();
private List<Integer> list5x4 = new ArrayList<>();
private List<Integer> list6x5 = new ArrayList<>();
private String description;
private int loser = 1;
private int piecetype;
private int firstslot = 0;
private int visitorpoints = 0;
private int ownerpoints = 0;
private int matchestowin = 0;
public MapleMiniGame(MapleCharacter owner, String description) {
this.owner = owner;
this.description = description;
}
public boolean hasFreeSlot() {
return visitor == null;
}
public boolean isOwner(MapleCharacter c) {
return owner.equals(c);
}
public void addVisitor(MapleCharacter challenger) {
visitor = challenger;
if (GameType.equals("omok")) {
this.getOwner().getClient().announce(MaplePacketCreator.getMiniGameNewVisitor(challenger, 1));
this.getOwner().getMap().broadcastMessage(MaplePacketCreator.addOmokBox(owner, 2, 0));
}
if (GameType.equals("matchcard")) {
this.getOwner().getClient().announce(MaplePacketCreator.getMatchCardNewVisitor(challenger, 1));
this.getOwner().getMap().broadcastMessage(MaplePacketCreator.addMatchCardBox(owner, 2, 0));
}
}
public void removeVisitor(MapleCharacter challenger) {
if (visitor == challenger) {
visitor = null;
this.getOwner().getClient().announce(MaplePacketCreator.getMiniGameRemoveVisitor());
if (GameType.equals("omok")) {
this.getOwner().getMap().broadcastMessage(MaplePacketCreator.addOmokBox(owner, 1, 0));
}
if (GameType.equals("matchcard")) {
this.getOwner().getMap().broadcastMessage(MaplePacketCreator.addMatchCardBox(owner, 1, 0));
}
}
}
public boolean isVisitor(MapleCharacter challenger) {
return visitor == challenger;
}
public void broadcastToVisitor(final byte[] packet) {
if (visitor != null) {
visitor.getClient().announce(packet);
}
}
public void setFirstSlot(int type) {
firstslot = type;
}
public int getFirstSlot() {
return firstslot;
}
public void setOwnerPoints() {
ownerpoints++;
if (ownerpoints + visitorpoints == matchestowin) {
if (ownerpoints == visitorpoints) {
this.broadcast(MaplePacketCreator.getMatchCardTie(this));
} else if (ownerpoints > visitorpoints) {
this.broadcast(MaplePacketCreator.getMatchCardOwnerWin(this));
} else {
this.broadcast(MaplePacketCreator.getMatchCardVisitorWin(this));
}
ownerpoints = 0;
visitorpoints = 0;
}
}
public void setVisitorPoints() {
visitorpoints++;
if (ownerpoints + visitorpoints == matchestowin) {
if (ownerpoints > visitorpoints) {
this.broadcast(MaplePacketCreator.getMiniGameOwnerWin(this));
} else if (visitorpoints > ownerpoints) {
this.broadcast(MaplePacketCreator.getMiniGameVisitorWin(this));
} else {
this.broadcast(MaplePacketCreator.getMiniGameTie(this));
}
ownerpoints = 0;
visitorpoints = 0;
}
}
public void setMatchesToWin(int type) {
matchestowin = type;
}
public void setPieceType(int type) {
piecetype = type;
}
public int getPieceType() {
return piecetype;
}
public void setGameType(String game) {
GameType = game;
if (game.equals("matchcard")) {
if (matchestowin == 6) {
for (int i = 0; i < 6; i++) {
list4x3.add(i);
list4x3.add(i);
}
} else if (matchestowin == 10) {
for (int i = 0; i < 10; i++) {
list5x4.add(i);
list5x4.add(i);
}
} else {
for (int i = 0; i < 15; i++) {
list6x5.add(i);
list6x5.add(i);
}
}
}
}
public String getGameType() {
return GameType;
}
public void shuffleList() {
if (matchestowin == 6) {
Collections.shuffle(list4x3);
} else if (matchestowin == 10) {
Collections.shuffle(list5x4);
} else {
Collections.shuffle(list6x5);
}
}
public int getCardId(int slot) {
int cardid;
if (matchestowin == 6) {
cardid = list4x3.get(slot - 1);
} else if (matchestowin == 10) {
cardid = list5x4.get(slot - 1);
} else {
cardid = list6x5.get(slot - 1);
}
return cardid;
}
public int getMatchesToWin() {
return matchestowin;
}
public void setLoser(int type) {
loser = type;
}
public int getLoser() {
return loser;
}
public void broadcast(final byte[] packet) {
if (owner.getClient() != null && owner.getClient().getSession() != null) {
owner.getClient().announce(packet);
}
broadcastToVisitor(packet);
}
public void chat(MapleClient c, String chat) {
broadcast(MaplePacketCreator.getPlayerShopChat(c.getPlayer(), chat, isOwner(c.getPlayer())));
}
public void sendOmok(MapleClient c, int type) {
c.announce(MaplePacketCreator.getMiniGame(c, this, isOwner(c.getPlayer()), type));
}
public void sendMatchCard(MapleClient c, int type) {
c.announce(MaplePacketCreator.getMatchCard(c, this, isOwner(c.getPlayer()), type));
}
public MapleCharacter getOwner() {
return owner;
}
public MapleCharacter getVisitor() {
return visitor;
}
public void setPiece(int move1, int move2, int type, MapleCharacter chr) {
int slot = move2 * 15 + move1 + 1;
if (piece[slot] == 0) {
piece[slot] = type;
this.broadcast(MaplePacketCreator.getMiniGameMoveOmok(this, move1, move2, type));
for (int y = 0; y < 15; y++) {
for (int x = 0; x < 11; x++) {
if (searchCombo(x, y, type)) {
if (this.isOwner(chr)) {
this.broadcast(MaplePacketCreator.getMiniGameOwnerWin(this));
this.setLoser(0);
} else {
this.broadcast(MaplePacketCreator.getMiniGameVisitorWin(this));
this.setLoser(1);
}
for (int y2 = 0; y2 < 15; y2++) {
for (int x2 = 0; x2 < 15; x2++) {
int slot2 = (y2 * 15 + x2 + 1);
piece[slot2] = 0;
}
}
}
}
}
for (int y = 0; y < 15; y++) {
for (int x = 4; x < 15; x++) {
if (searchCombo2(x, y, type)) {
if (this.isOwner(chr)) {
this.broadcast(MaplePacketCreator.getMiniGameOwnerWin(this));
this.setLoser(0);
} else {
this.broadcast(MaplePacketCreator.getMiniGameVisitorWin(this));
this.setLoser(1);
}
for (int y2 = 0; y2 < 15; y2++) {
for (int x2 = 0; x2 < 15; x2++) {
int slot2 = (y2 * 15 + x2 + 1);
piece[slot2] = 0;
}
}
}
}
}
}
}
private boolean searchCombo(int x, int y, int type) {
int slot = y * 15 + x + 1;
for (int i = 0; i < 5; i++) {
if (piece[slot + i] == type) {
if (i == 4) {
return true;
}
} else {
break;
}
}
for (int j = 15; j < 17; j++) {
for (int i = 0; i < 5; i++) {
if (piece[slot + i * j] == type) {
if (i == 4) {
return true;
}
} else {
break;
}
}
}
return false;
}
private boolean searchCombo2(int x, int y, int type) {
int slot = y * 15 + x + 1;
for (int j = 14; j < 15; j++) {
for (int i = 0; i < 5; i++) {
if (piece[slot + i * j] == type) {
if (i == 4) {
return true;
}
} else {
break;
}
}
}
return false;
}
public String getDescription() {
return description;
}
@Override
public void sendDestroyData(MapleClient client) {
}
@Override
public void sendSpawnData(MapleClient client) {
}
@Override
public MapleMapObjectType getType() {
return MapleMapObjectType.MINI_GAME;
}
}
+491
View File
@@ -0,0 +1,491 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 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 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 client.MapleCharacter;
import client.MapleClient;
import client.inventory.Item;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import tools.locks.MonitoredReentrantLock;
import net.SendOpcode;
import server.MapleInventoryManipulator;
import server.maps.AbstractMapleMapObject;
import server.maps.MapleMapObjectType;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.data.output.MaplePacketLittleEndianWriter;
import tools.locks.MonitoredLockType;
/**
*
* @author Matze
* @author Ronan (concurrency protection)
*/
public class MaplePlayerShop extends AbstractMapleMapObject {
private AtomicBoolean open = new AtomicBoolean(false);
private MapleCharacter owner;
private MapleCharacter[] visitors = new MapleCharacter[3];
private List<MaplePlayerShopItem> items = new ArrayList<>();
private String description;
private int boughtnumber = 0;
private List<String> bannedList = new ArrayList<>();
private List<Pair<MapleCharacter, String>> chatLog = new LinkedList<>();
private Map<Integer, Byte> chatSlot = new LinkedHashMap<>();
private Lock visitorLock = new MonitoredReentrantLock(MonitoredLockType.VISITOR_PSHOP, true);
public MaplePlayerShop(MapleCharacter owner, String description) {
this.setPosition(owner.getPosition());
this.owner = owner;
this.description = description;
}
public int getChannel() {
return owner.getClient().getChannel();
}
public int getMapId() {
return owner.getMapId();
}
public boolean isOpen() {
return open.get();
}
public void setOpen(boolean openShop) {
open.set(openShop);
}
public boolean hasFreeSlot() {
visitorLock.lock();
try {
return visitors[0] == null || visitors[1] == null || visitors[2] == null;
} finally {
visitorLock.unlock();
}
}
public boolean isOwner(MapleCharacter c) {
return owner.equals(c);
}
private void addVisitor(MapleCharacter visitor) {
visitorLock.lock();
try {
for (int i = 0; i < 3; i++) {
if (visitors[i] == null) {
visitors[i] = visitor;
visitor.setSlot(i);
this.broadcast(MaplePacketCreator.getPlayerShopNewVisitor(visitor, i + 1));
if(i == 2) visitor.getMap().broadcastMessage(MaplePacketCreator.addCharBox(this.getOwner(), 1));
break;
}
}
} finally {
visitorLock.unlock();
}
}
public void forceRemoveVisitor(MapleCharacter visitor) {
if (visitor == owner) {
owner.getMap().removeMapObject(this);
owner.setPlayerShop(null);
}
visitorLock.lock();
try {
for (int i = 0; i < 3; i++) {
if (visitors[i] != null && visitors[i].getId() == visitor.getId()) {
visitors[i] = null;
visitor.setSlot(-1);
this.broadcast(MaplePacketCreator.getPlayerShopRemoveVisitor(i + 1));
return;
}
}
} finally {
visitorLock.unlock();
}
}
public void removeVisitor(MapleCharacter visitor) {
if (visitor == owner) {
owner.getMap().removeMapObject(this);
owner.setPlayerShop(null);
} else {
visitorLock.lock();
try {
for (int i = 0; i < 3; i++) {
if (visitors[i] != null && visitors[i].getId() == visitor.getId()) {
visitor.setSlot(-1); //absolutely cant remove player slot for late players without dc'ing them... heh
for(int j = i; j < 2; j++) {
if(visitors[j] != null) owner.announce(MaplePacketCreator.getPlayerShopRemoveVisitor(j + 1));
visitors[j] = visitors[j + 1];
if(visitors[j] != null) visitors[j].setSlot(j);
}
visitors[2] = null;
for(int j = i; j < 2; j++) {
if(visitors[j] != null) owner.announce(MaplePacketCreator.getPlayerShopNewVisitor(visitors[j], j + 1));
}
this.broadcastRestoreToVisitors();
return;
}
}
} finally {
visitorLock.unlock();
}
if(this.getOwner().getPlayerShop() != null) visitor.getMap().broadcastMessage(MaplePacketCreator.addCharBox(this.getOwner(), 4));
}
}
public boolean isVisitor(MapleCharacter visitor) {
visitorLock.lock();
try {
return visitors[0] == visitor || visitors[1] == visitor || visitors[2] == visitor;
} finally {
visitorLock.unlock();
}
}
public void addItem(MaplePlayerShopItem item) {
synchronized (items) {
items.add(item);
}
}
public void removeItem(int item) {
synchronized (items) {
items.remove(item);
}
}
/**
* no warnings for now o.o
* @param c
* @param item
* @param quantity
*/
public void buy(MapleClient c, int item, short quantity) {
synchronized (items) {
if (isVisitor(c.getPlayer())) {
MaplePlayerShopItem pItem = items.get(item);
Item newItem = pItem.getItem().copy();
newItem.setQuantity(newItem.getQuantity());
if (quantity < 1 || pItem.getBundles() < 1 || newItem.getQuantity() > pItem.getBundles() || !pItem.isExist()) {
return;
} else if (newItem.getType() == 1 && newItem.getQuantity() > 1) {
return;
}
synchronized (c.getPlayer()) {
if (c.getPlayer().getMeso() >= (long) pItem.getPrice() * quantity) {
if (MapleInventoryManipulator.addFromDrop(c, newItem, false)) {
c.getPlayer().gainMeso(-pItem.getPrice() * quantity, false);
owner.gainMeso(pItem.getPrice() * quantity, true);
pItem.setBundles((short) (pItem.getBundles() - quantity));
if (pItem.getBundles() < 1) {
pItem.setDoesExist(false);
if (++boughtnumber == items.size()) {
owner.setPlayerShop(null);
this.setOpen(false);
this.closeShop();
owner.dropMessage(1, "Your items are sold out, and therefore your shop is closed.");
}
}
} else {
c.getPlayer().dropMessage(1, "Your inventory is full. Please clean a slot before buying this item.");
}
}
}
}
}
}
public void broadcastToVisitors(final byte[] packet) {
visitorLock.lock();
try {
for (int i = 0; i < 3; i++) {
if (visitors[i] != null) {
visitors[i].getClient().announce(packet);
}
}
} finally {
visitorLock.unlock();
}
}
public void broadcastRestoreToVisitors() {
visitorLock.lock();
try {
for (int i = 0; i < 3; i++) {
if (visitors[i] != null) {
visitors[i].getClient().announce(MaplePacketCreator.getPlayerShopRemoveVisitor(i + 1));
}
}
for (int i = 0; i < 3; i++) {
if (visitors[i] != null) {
visitors[i].getClient().announce(MaplePacketCreator.getPlayerShop(this, false));
}
}
recoverChatLog();
} finally {
visitorLock.unlock();
}
}
public void removeVisitors() {
List<MapleCharacter> visitorList = new ArrayList<>(3);
visitorLock.lock();
try {
try {
for (int i = 0; i < 3; i++) {
if (visitors[i] != null) {
visitors[i].getClient().announce(MaplePacketCreator.shopErrorMessage(10, 1));
visitorList.add(visitors[i]);
}
}
} catch (Exception e) {
e.printStackTrace();
}
} finally {
visitorLock.unlock();
}
for(MapleCharacter mc : visitorList) forceRemoveVisitor(mc);
if (owner != null) {
forceRemoveVisitor(getOwner());
}
}
public static byte[] shopErrorMessage(int error, int type) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
mplew.write(0x0A);
mplew.write(type);
mplew.write(error);
return mplew.getPacket();
}
public void broadcast(final byte[] packet) {
if (owner.getClient() != null && owner.getClient().getSession() != null) {
owner.getClient().announce(packet);
}
broadcastToVisitors(packet);
}
private byte getVisitorSlot(MapleCharacter chr) {
byte s = 0;
for (MapleCharacter mc : getVisitors()) {
s++;
if (mc != null) {
if (mc.getName().equalsIgnoreCase(chr.getName())) {
break;
}
} else if (s == 3) {
s = 0;
}
}
return s;
}
public void chat(MapleClient c, String chat) {
byte s = getVisitorSlot(c.getPlayer());
synchronized(chatLog) {
chatLog.add(new Pair<>(c.getPlayer(), chat));
if(chatLog.size() > 25) chatLog.remove(0);
chatSlot.put(c.getPlayer().getId(), s);
}
broadcast(MaplePacketCreator.getPlayerShopChat(c.getPlayer(), chat, s));
}
private void recoverChatLog() {
synchronized(chatLog) {
for(Pair<MapleCharacter, String> it : chatLog) {
MapleCharacter chr = it.getLeft();
Byte pos = chatSlot.get(chr.getId());
broadcastToVisitors(MaplePacketCreator.getPlayerShopChat(chr, it.getRight(), pos));
}
}
}
private void clearChatLog() {
synchronized(chatLog) {
chatLog.clear();
}
}
public void closeShop() {
owner.getMap().broadcastMessage(MaplePacketCreator.removeCharBox(owner));
clearChatLog();
removeVisitors();
}
public void sendShop(MapleClient c) {
visitorLock.lock();
try {
c.announce(MaplePacketCreator.getPlayerShop(this, isOwner(c.getPlayer())));
} finally {
visitorLock.unlock();
}
}
public MapleCharacter getOwner() {
return owner;
}
public MapleCharacter[] getVisitors() {
visitorLock.lock();
try {
MapleCharacter[] copy = new MapleCharacter[3];
for(int i = 0; i < visitors.length; i++) copy[i] = visitors[i];
return copy;
} finally {
visitorLock.unlock();
}
}
public List<MaplePlayerShopItem> getItems() {
synchronized (items) {
return Collections.unmodifiableList(items);
}
}
public boolean hasItem(int itemid) {
for(MaplePlayerShopItem mpsi : getItems()) {
if(mpsi.getItem().getItemId() == itemid && mpsi.isExist() && mpsi.getBundles() > 0) {
return true;
}
}
return false;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public void banPlayer(String name) {
if (!bannedList.contains(name)) {
bannedList.add(name);
}
MapleCharacter target = null;
visitorLock.lock();
try {
for (int i = 0; i < 3; i++) {
if (visitors[i] != null && visitors[i].getName().equals(name)) {
target = visitors[i];
break;
}
}
} finally {
visitorLock.unlock();
}
if(target != null) {
target.getClient().announce(MaplePacketCreator.shopErrorMessage(5, 1));
removeVisitor(target);
}
}
public boolean isBanned(String name) {
return bannedList.contains(name);
}
public synchronized boolean visitShop(MapleCharacter chr) {
if(!open.get()) {
chr.dropMessage(1, "This store is not yet open.");
return false;
}
if (this.isBanned(chr.getName())) {
chr.dropMessage(1, "You have been banned from this store.");
return false;
}
visitorLock.lock();
try {
if (this.hasFreeSlot() && !this.isVisitor(chr)) {
this.addVisitor(chr);
chr.setPlayerShop(this);
this.sendShop(chr.getClient());
return true;
}
return false;
} finally {
visitorLock.unlock();
}
}
public List<MaplePlayerShopItem> sendAvailableBundles(int itemid) {
List<MaplePlayerShopItem> list = new LinkedList<>();
List<MaplePlayerShopItem> all = new ArrayList<>();
synchronized (items) {
for(MaplePlayerShopItem mpsi : items) all.add(mpsi);
}
for(MaplePlayerShopItem mpsi : all) {
if(mpsi.getItem().getItemId() == itemid && mpsi.getBundles() > 0 && mpsi.isExist()) {
list.add(mpsi);
}
}
return list;
}
@Override
public void sendDestroyData(MapleClient client) {
client.announce(MaplePacketCreator.removeCharBox(this.getOwner()));
}
@Override
public void sendSpawnData(MapleClient client) {
client.announce(MaplePacketCreator.addCharBox(this.getOwner(), 4));
}
@Override
public MapleMapObjectType getType() {
return MapleMapObjectType.SHOP;
}
}
+66
View File
@@ -0,0 +1,66 @@
/*
This file is part of the OdinMS Maple Story Server
Copyright (C) 2008 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 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 client.inventory.Item;
/**
*
* @author Matze
*/
public class MaplePlayerShopItem {
private Item item;
private short bundles;
private int price;
private boolean doesExist;
public MaplePlayerShopItem(Item item, short bundles, int price) {
this.item = item;
this.bundles = bundles;
this.price = price;
this.doesExist = true;
}
public void setDoesExist(boolean tf) {
this.doesExist = tf;
}
public boolean isExist() {
return doesExist;
}
public Item getItem() {
return item;
}
public short getBundles() {
return bundles;
}
public int getPrice() {
return price;
}
public void setBundles(short bundles) {
this.bundles = bundles;
}
}
+6 -7
View File
@@ -162,18 +162,19 @@ public class MapleReactor extends AbstractMapleMapObject {
return MaplePacketCreator.spawnReactor(this);
}
public void resetReactorActions() {
public void resetReactorActions(int newState) {
setState((byte) newState);
cancelReactorTimeout();
setShouldCollect(true);
refreshReactorTimeout();
if(map != null) map.searchItemReactors(this);
}
public void forceHitReactor(final byte newState) {
this.lockReactor();
try {
setState((byte) newState);
this.resetReactorActions();
this.resetReactorActions(newState);
map.broadcastMessage(MaplePacketCreator.triggerReactor(this, (short) 0));
} finally {
this.unlockReactor();
@@ -184,9 +185,7 @@ public class MapleReactor extends AbstractMapleMapObject {
if(!this.reactorLock.tryLock()) return;
try {
setState((byte) newState);
this.resetReactorActions();
this.resetReactorActions(newState);
map.broadcastMessage(MaplePacketCreator.triggerReactor(this, (short) 0));
} finally {
this.unlockReactor();