Poison/slow update + Map-persistent diseases + Selling zero-qty rechs.
Rebalanced CafePQ rewards. Rebalanced drop chance of some equipments and HT drops with high rates. Fixed an weird issue where a "Targa hat" would appear as a debuff effect. Added visual effect to be displayed to other players when the custom "Chair Mastery" skill is being used. Slow disease is now visible to other players. Poison damage now displays the correct damage amount to other players. Disease status are now visible for other players when changing maps. Fixed recharging price being accounted incorrectly. Fixed zero-quantity rechargeables not being able to sell at NPC shops.
This commit is contained in:
@@ -26,6 +26,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import server.life.MobSkill;
|
||||
import tools.Pair;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
|
||||
@@ -38,7 +40,7 @@ public class PlayerBuffStorage {
|
||||
private int id = (int) (Math.random() * 100);
|
||||
private final Lock lock = new MonitoredReentrantLock(MonitoredLockType.BUFF_STORAGE, true);
|
||||
private Map<Integer, List<PlayerBuffValueHolder>> buffs = new HashMap<>();
|
||||
private Map<Integer, Map<MapleDisease, Long>> diseases = new HashMap<>();
|
||||
private Map<Integer, Map<MapleDisease, Pair<Long, MobSkill>>> diseases = new HashMap<>();
|
||||
|
||||
public void addBuffsToStorage(int chrid, List<PlayerBuffValueHolder> toStore) {
|
||||
lock.lock();
|
||||
@@ -58,7 +60,7 @@ public class PlayerBuffStorage {
|
||||
}
|
||||
}
|
||||
|
||||
public void addDiseasesToStorage(int chrid, Map<MapleDisease, Long> toStore) {
|
||||
public void addDiseasesToStorage(int chrid, Map<MapleDisease, Pair<Long, MobSkill>> toStore) {
|
||||
lock.lock();
|
||||
try {
|
||||
diseases.put(chrid, toStore);
|
||||
@@ -67,7 +69,7 @@ public class PlayerBuffStorage {
|
||||
}
|
||||
}
|
||||
|
||||
public Map<MapleDisease, Long> getDiseasesFromStorage(int chrid) {
|
||||
public Map<MapleDisease, Pair<Long, MobSkill>> getDiseasesFromStorage(int chrid) {
|
||||
lock.lock();
|
||||
try {
|
||||
return diseases.remove(chrid);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
package net.server;
|
||||
|
||||
import net.server.worker.CharacterDiseaseWorker;
|
||||
import net.server.worker.CouponWorker;
|
||||
import net.server.worker.RankingWorker;
|
||||
import java.io.FileInputStream;
|
||||
@@ -94,9 +95,12 @@ public class Server {
|
||||
private final Map<MapleClient, Long> inLoginState = new HashMap<>(100);
|
||||
private final Lock srvLock = new MonitoredReentrantLock(MonitoredLockType.SERVER);
|
||||
private final Lock lgnLock = new MonitoredReentrantLock(MonitoredLockType.SERVER);
|
||||
private final Lock disLock = new MonitoredReentrantLock(MonitoredLockType.SERVER);
|
||||
private final PlayerBuffStorage buffStorage = new PlayerBuffStorage();
|
||||
private final Map<Integer, MapleAlliance> alliances = new HashMap<>(100);
|
||||
private final Map<Integer, NewYearCardRecord> newyears = new HashMap<>();
|
||||
private final List<MapleClient> processDiseaseAnnouncePlayers = new LinkedList<>();
|
||||
private final List<MapleClient> registeredDiseaseAnnouncePlayers = new LinkedList<>();
|
||||
|
||||
private boolean online = false;
|
||||
public static long uptime = System.currentTimeMillis();
|
||||
@@ -261,7 +265,39 @@ public class Server {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void runAnnouncePlayerDiseasesSchedule() {
|
||||
disLock.lock();
|
||||
try {
|
||||
while(!processDiseaseAnnouncePlayers.isEmpty()) {
|
||||
MapleClient c = processDiseaseAnnouncePlayers.remove(0);
|
||||
MapleCharacter player = c.getPlayer();
|
||||
if(player != null && player.isLoggedinWorld()) {
|
||||
for(MapleCharacter chr : player.getMap().getCharacters()) {
|
||||
chr.announceDiseases(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is to force the system to wait for at least one complete tick before releasing disease info for the registered clients
|
||||
while(!registeredDiseaseAnnouncePlayers.isEmpty()) {
|
||||
MapleClient c = registeredDiseaseAnnouncePlayers.remove(0);
|
||||
processDiseaseAnnouncePlayers.add(c);
|
||||
}
|
||||
} finally {
|
||||
disLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerAnnouncePlayerDiseases(MapleClient c) {
|
||||
disLock.lock();
|
||||
try {
|
||||
registeredDiseaseAnnouncePlayers.add(c);
|
||||
} finally {
|
||||
disLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
Properties p = new Properties();
|
||||
try {
|
||||
@@ -306,6 +342,7 @@ public class Server {
|
||||
disconnectIdlesOnLoginTask();
|
||||
|
||||
long timeLeft = getTimeLeftForNextHour();
|
||||
tMan.register(new CharacterDiseaseWorker(), 777, 777);
|
||||
tMan.register(new CouponWorker(), ServerConstants.COUPON_INTERVAL, timeLeft);
|
||||
tMan.register(new RankingWorker(), ServerConstants.RANKING_INTERVAL, timeLeft);
|
||||
|
||||
|
||||
@@ -36,13 +36,17 @@ public final class CancelChairHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
if (id == -1) { // Cancel Chair
|
||||
mc.setChair(0);
|
||||
mc.unregisterChairBuff();
|
||||
if(mc.unregisterChairBuff()) {
|
||||
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.cancelForeignChairSkillEffect(mc.getId()), false);
|
||||
}
|
||||
|
||||
c.announce(MaplePacketCreator.cancelChair(-1));
|
||||
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showChair(c.getPlayer().getId(), 0), false);
|
||||
} else { // Use In-Map Chair
|
||||
mc.setChair(id);
|
||||
mc.registerChairBuff();
|
||||
if(mc.registerChairBuff()) {
|
||||
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.giveForeignChairSkillEffect(mc.getId()), false);
|
||||
}
|
||||
|
||||
c.announce(MaplePacketCreator.cancelChair(id));
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import client.inventory.Equip;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import constants.ItemConstants;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
@@ -64,6 +65,12 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if(ItemConstants.isCashStore(cItem.getItemId()) && chr.getLevel() < 16) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if (action == 0x03) { // Item
|
||||
Item item = cItem.toItem();
|
||||
cs.addToInventory(item);
|
||||
@@ -176,20 +183,20 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
}
|
||||
} else if (action == 0x08) { // Increase Character Slots
|
||||
slea.skip(1);
|
||||
int cash = slea.readInt();
|
||||
CashItem cItem = CashItemFactory.getItem(slea.readInt());
|
||||
slea.skip(1);
|
||||
int cash = slea.readInt();
|
||||
CashItem cItem = CashItemFactory.getItem(slea.readInt());
|
||||
|
||||
if (!canBuy(cItem, cs.getCash(cash))) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
if (!canBuy(cItem, cs.getCash(cash))) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if (c.gainCharacterSlot()) {
|
||||
c.announce(MaplePacketCreator.showBoughtCharacterSlot(c.getCharacterSlots()));
|
||||
cs.gainCash(cash, -cItem.getPrice());
|
||||
c.announce(MaplePacketCreator.showCash(chr));
|
||||
}
|
||||
if (c.gainCharacterSlot()) {
|
||||
c.announce(MaplePacketCreator.showBoughtCharacterSlot(c.getCharacterSlots()));
|
||||
cs.gainCash(cash, -cItem.getPrice());
|
||||
c.announce(MaplePacketCreator.showCash(chr));
|
||||
}
|
||||
} else if (action == 0x0D) { // Take from Cash Inventory
|
||||
Item item = cs.findByCashId(slea.readInt());
|
||||
if (item == null) {
|
||||
@@ -281,8 +288,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
c.announce(MaplePacketCreator.showCash(c.getPlayer()));
|
||||
} else if (action == 0x23) { //Friendship :3
|
||||
slea.readInt(); //Birthday
|
||||
// if (checkBirthday(c, birthday)) {
|
||||
slea.readInt(); //Birthday
|
||||
// if (checkBirthday(c, birthday)) {
|
||||
int payment = slea.readByte();
|
||||
slea.skip(3); //0s
|
||||
int snID = slea.readInt();
|
||||
|
||||
@@ -106,7 +106,7 @@ public final class NewYearCardHandler extends AbstractMaplePacketHandler {
|
||||
player.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(player, newyear, 0xD, 0));
|
||||
|
||||
MapleCharacter sender = c.getWorldServer().getPlayerStorage().getCharacterById(newyear.getSenderId());
|
||||
if(sender != null && sender.isLoggedin() && !sender.isAwayFromWorld()) {
|
||||
if(sender != null && sender.isLoggedinWorld()) {
|
||||
sender.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(sender, newyear, 0xD, 0));
|
||||
sender.dropMessage(6, "[NEW YEAR] Your addressee successfully received the New Year card.");
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import server.life.MobSkill;
|
||||
|
||||
public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@@ -129,7 +130,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
player.silentGiveBuffs(timedBuffs);
|
||||
}
|
||||
|
||||
Map<MapleDisease, Long> diseases = server.getPlayerBuffStorage().getDiseasesFromStorage(cid);
|
||||
Map<MapleDisease, Pair<Long, MobSkill>> diseases = server.getPlayerBuffStorage().getDiseasesFromStorage(cid);
|
||||
if (diseases != null) {
|
||||
player.silentApplyDiseases(diseases);
|
||||
}
|
||||
|
||||
33
src/net/server/worker/CharacterDiseaseWorker.java
Normal file
33
src/net/server/worker/CharacterDiseaseWorker.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
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
|
||||
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 net.server.worker;
|
||||
|
||||
import net.server.Server;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
* @info Thread responsible for announcing other players diseases when one enters into a map
|
||||
*/
|
||||
public class CharacterDiseaseWorker implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
Server.getInstance().runAnnouncePlayerDiseasesSchedule();
|
||||
}
|
||||
}
|
||||
@@ -842,7 +842,7 @@ public class World {
|
||||
|
||||
for(Map.Entry<Integer, Byte> dp: deployedPets.entrySet()) {
|
||||
MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey() / 4);
|
||||
if(chr == null || !chr.isLoggedin() || chr.isAwayFromWorld()) continue;
|
||||
if(chr == null || !chr.isLoggedinWorld()) continue;
|
||||
|
||||
Byte dpVal = (byte)(dp.getValue() + 1);
|
||||
if(dpVal == ServerConstants.PET_EXHAUST_COUNT) {
|
||||
@@ -900,7 +900,7 @@ public class World {
|
||||
|
||||
for(Map.Entry<Integer, Byte> dp: deployedMounts.entrySet()) {
|
||||
MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey());
|
||||
if(chr == null || !chr.isLoggedin() || chr.isAwayFromWorld()) continue;
|
||||
if(chr == null || !chr.isLoggedinWorld()) continue;
|
||||
|
||||
Byte dpVal = (byte)(dp.getValue() + 1);
|
||||
if(dpVal == ServerConstants.MOUNT_EXHAUST_COUNT) {
|
||||
|
||||
Reference in New Issue
Block a user