Map chair skill + Hired Merchant fix

Changed map chair bonus healing mechanic to be a player skill, instead of promptly available for all players (healing buff takes place only if the player has the skill). Hired Merchant now properly checks for a space on the inventory before permitting a player to buy an item/bundle. Minor fix with concurrency on MapleStorage.
This commit is contained in:
ronancpl
2017-10-22 01:08:40 -02:00
parent 75e11e1996
commit e993c8c7b0
63 changed files with 354 additions and 191 deletions

View File

@@ -63,7 +63,7 @@ public enum MapleBuffStat {
BERSERK_FURY(0x8000000L),
DIVINE_BODY(0x10000000L),
SPARK(0x20000000L),
//0x40000000L
MAP_CHAIR(0x40000000L),
FINALATTACK(0x80000000L),
BATTLESHIP(0xA00000040L), // weird one
WATK(0x100000000L),

View File

@@ -121,6 +121,7 @@ import constants.GameConstants;
import constants.ItemConstants;
import constants.ServerConstants;
import constants.skills.Aran;
import constants.skills.Beginner;
import constants.skills.Bishop;
import constants.skills.BlazeWizard;
import constants.skills.Bowmaster;
@@ -135,10 +136,12 @@ import constants.skills.GM;
import constants.skills.Hermit;
import constants.skills.Hero;
import constants.skills.ILArchMage;
import constants.skills.Legend;
import constants.skills.Magician;
import constants.skills.Marauder;
import constants.skills.Marksman;
import constants.skills.NightLord;
import constants.skills.Noblesse;
import constants.skills.Paladin;
import constants.skills.Priest;
import constants.skills.Ranger;
@@ -1248,7 +1251,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private void changeMapInternal(final MapleMap to, final Point pos, final byte[] warpPacket) {
if(!canWarpMap) return;
this.stopChairTask();
this.unregisterChairBuff();
this.clearBanishPlayerData();
this.closePlayerInteractions();
this.resetPlayerAggro();
@@ -2994,6 +2997,8 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
prtLock.unlock();
}
}
} else if (effect.isMapChair()) {
stopChairTask();
}
List<Pair<MapleBuffStat, MapleBuffStatValueHolder>> toCancel = deregisterBuffStats(buffstats);
@@ -3263,6 +3268,8 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
stopExtraTask();
startExtraTask(extraHpRec, extraMpRec, extraRecInterval); // HP & MP sharing the same task holder
}
} else if (effect.isMapChair()) {
startChairTask();
}
effLock.lock();
@@ -3324,7 +3331,36 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
recalcLocalStats();
}
private static int getJobMapChair(MapleJob job) {
switch(job.getId() / 1000) {
case 0:
return Beginner.MAP_CHAIR;
case 1:
return Noblesse.MAP_CHAIR;
default:
return Legend.MAP_CHAIR;
}
}
public void unregisterChairBuff() {
int skillId = getJobMapChair(job);
int skillLv = getSkillLevel(skillId);
if(skillLv > 0) {
MapleStatEffect mapChairSkill = SkillFactory.getSkill(skillId).getEffect(skillLv);
cancelEffect(mapChairSkill, false, -1);
}
}
public void registerChairBuff() {
int skillId = getJobMapChair(job);
int skillLv = getSkillLevel(skillId);
if(skillLv > 0) {
MapleStatEffect mapChairSkill = SkillFactory.getSkill(skillId).getEffect(skillLv);
mapChairSkill.applyTo(this);
}
}
public int getChair() {
return chair.get();
}

View File

@@ -1316,7 +1316,6 @@ public class MapleClient {
player.cancelBuffExpireTask();
player.cancelDiseaseExpireTask();
player.cancelSkillCooldownTask();
player.stopChairTask();
//Cancelling magicdoor? Nope
//Cancelling mounts? Noty
if (player.getBuffedValue(MapleBuffStat.PUPPET) != null) {

View File

@@ -74,9 +74,7 @@ import constants.skills.WhiteKnight;
import constants.skills.WindArcher;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import provider.MapleData;
@@ -189,6 +187,7 @@ public class SkillFactory {
case Beginner.NIMBLE_FEET:
case Beginner.MONSTER_RIDER:
case Beginner.ECHO_OF_HERO:
case Beginner.MAP_CHAIR:
case Swordsman.IRON_BODY:
case Fighter.AXE_BOOSTER:
case Fighter.POWER_GUARD:
@@ -303,6 +302,7 @@ public class SkillFactory {
case Noblesse.MONSTER_RIDER:
case Noblesse.NIMBLE_FEET:
case Noblesse.RECOVERY:
case Noblesse.MAP_CHAIR:
case DawnWarrior.COMBO:
case DawnWarrior.FINAL_ATTACK:
case DawnWarrior.IRON_BODY:
@@ -346,6 +346,7 @@ public class SkillFactory {
case Legend.ECHO_OF_HERO:
case Legend.RECOVERY:
case Legend.MONSTER_RIDER:
case Legend.MAP_CHAIR:
case Aran.MAPLE_WARRIOR:
case Aran.HEROS_WILL:
case Aran.POLEARM_BOOSTER:

View File

@@ -28,6 +28,7 @@ package constants.skills;
public class Beginner {
public static final int BLESSING_OF_THE_FAIRY = 12;
public static final int FOLLOW_THE_LEADER = 8;
public static final int MAP_CHAIR = 100;
public static final int THREE_SNAILS = 1001;
public static final int RECOVERY = 1001;
public static final int NIMBLE_FEET = 1002;

View File

@@ -4,7 +4,7 @@ public class Evan {
// EVAN1
public static final int BLESSING_OF_THE_FAIRY = 20010012;
public static final int THREE_SNAILS = 20011000;
public static final int RECOVERY = 20011001;
public static final int RECOVERY = 20011001;
public static final int NIMBLE_FEET = 20011002;
public static final int LEGENDARY_SPIRIT = 20011003;
public static final int MONSTER_RIDER = 20011004;

View File

@@ -44,6 +44,7 @@ public class Legend {
public static final int TUTORIAL_SKILL3 = 20000016;
public static final int TUTORIAL_SKILL4 = 20000017; //combo
public static final int TUTORIAL_SKILL5 = 20000018; //critical
public static final int MAP_CHAIR = 20000100;
public static final int YETI_MOUNT1 = 20001019;
public static final int YETI_MOUNT2 = 20001022;
public static final int WITCH_BROOMSTICK = 20001023;

View File

@@ -27,6 +27,7 @@ package constants.skills;
*/
public class Noblesse {
public static final int BLESSING_OF_THE_FAIRY = 10000012;
public static final int MAP_CHAIR = 10000100;
public static final int THREE_SNAILS = 10001000;
public static final int RECOVERY = 10001001;
public static final int NIMBLE_FEET = 10001002;

View File

@@ -22,23 +22,28 @@
package net.server.channel.handlers;
import client.MapleClient;
import client.MapleCharacter;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CancelChairHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int id = slea.readShort();
MapleCharacter mc = c.getPlayer();
if (id == -1) { // Cancel Chair
c.getPlayer().setChair(0);
c.getPlayer().stopChairTask();
mc.setChair(0);
mc.unregisterChairBuff();
c.announce(MaplePacketCreator.cancelChair(-1));
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showChair(c.getPlayer().getId(), 0), false);
} else { // Use In-Map Chair
c.getPlayer().setChair(id);
c.getPlayer().startChairTask();
mc.setChair(id);
mc.registerChairBuff();
c.announce(MaplePacketCreator.cancelChair(id));
}
}

View File

@@ -32,6 +32,7 @@ import tools.data.input.SeekableLittleEndianAccessor;
* @author Matze
*/
public final class NPCMoreTalkHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte lastMsg = slea.readByte(); // 00 (last msg type I think)
byte action = slea.readByte(); // 00 = end chat, 01 == follow

View File

@@ -33,6 +33,7 @@ import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class NPCTalkHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (!c.getPlayer().isAlive()) {
c.announce(MaplePacketCreator.enableActions());

View File

@@ -26,7 +26,6 @@ import client.MapleClient;
import net.AbstractMaplePacketHandler;
import scripting.quest.QuestScriptManager;
import server.quest.MapleQuest;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
@@ -34,6 +33,7 @@ import tools.data.input.SeekableLittleEndianAccessor;
* @author Matze
*/
public final class QuestActionHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte action = slea.readByte();
short questid = slea.readShort();

View File

@@ -266,7 +266,9 @@ public class MapleStatEffect {
}
}
} else {
if((sourceid == Beginner.NIMBLE_FEET || sourceid == Noblesse.NIMBLE_FEET || sourceid == Evan.NIMBLE_FEET || sourceid == Legend.AGILE_BODY) && ServerConstants.USE_ULTRA_NIMBLE_FEET == true) {
if(isMapChair(sourceid)) {
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MAP_CHAIR, 1);
} else if((sourceid == Beginner.NIMBLE_FEET || sourceid == Noblesse.NIMBLE_FEET || sourceid == Evan.NIMBLE_FEET || sourceid == Legend.AGILE_BODY) && ServerConstants.USE_ULTRA_NIMBLE_FEET == true) {
ret.jump = (short)(ret.speed * 4);
ret.speed *= 15;
}
@@ -756,8 +758,7 @@ public class MapleStatEffect {
applyto.dispelDebuff(MapleDisease.SEDUCE);
applyto.dispelDebuff(MapleDisease.ZOMBIFY);
applyto.dispelDebuffs();
}
if (isComboReset()) {
} else if (isComboReset()) {
applyto.setCombo((short) 0);
}
/*if (applyfrom.getMp() < getMpCon()) {
@@ -1322,6 +1323,15 @@ public class MapleStatEffect {
return sourceid == Beginner.RECOVERY || sourceid == Noblesse.RECOVERY || sourceid == Legend.RECOVERY || sourceid == Evan.RECOVERY;
}
public boolean isMapChair() {
return sourceid == Beginner.MAP_CHAIR || sourceid == Noblesse.MAP_CHAIR || sourceid == Legend.MAP_CHAIR;
}
public static boolean isMapChair(int sourceid) {
return sourceid == Beginner.MAP_CHAIR || sourceid == Noblesse.MAP_CHAIR || sourceid == Legend.MAP_CHAIR;
}
public boolean isDojoBuff() {
return sourceid >= 2022359 && sourceid <= 2022421;
}

View File

@@ -3,19 +3,16 @@
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/>.
*/
@@ -164,12 +161,13 @@ public class MapleStorage {
lock.lock();
try {
ret = items.remove(slot);
MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(ret.getItemId());
typeItems.put(type, new ArrayList<>(filterItems(type)));
} finally {
lock.unlock();
}
MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(ret.getItemId());
typeItems.put(type, new ArrayList<>(filterItems(type)));
return ret;
}
@@ -177,12 +175,12 @@ public class MapleStorage {
lock.lock();
try {
items.add(item);
MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId());
typeItems.put(type, new ArrayList<>(filterItems(type)));
} finally {
lock.unlock();
}
MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(item.getItemId());
typeItems.put(type, new ArrayList<>(filterItems(type)));
}
public List<Item> getItems() {
@@ -208,15 +206,20 @@ public class MapleStorage {
}
public byte getSlot(MapleInventoryType type, byte slot) {
byte ret = 0;
List<Item> storageItems = getItems();
for (Item item : storageItems) {
if (item == typeItems.get(type).get(slot)) {
return ret;
lock.lock();
try {
byte ret = 0;
List<Item> storageItems = getItems();
for (Item item : storageItems) {
if (item == typeItems.get(type).get(slot)) {
return ret;
}
ret++;
}
ret++;
return -1;
} finally {
lock.unlock();
}
return -1;
}
public void sendStorage(MapleClient c, int npcId) {
@@ -235,23 +238,33 @@ public class MapleStorage {
return 1;
}
});
List<Item> storageItems = getItems();
for (MapleInventoryType type : MapleInventoryType.values()) {
typeItems.put(type, new ArrayList<>(storageItems));
}
c.announce(MaplePacketCreator.getStorage(npcId, slots, storageItems, meso));
} finally {
lock.unlock();
}
List<Item> storageItems = getItems();
for (MapleInventoryType type : MapleInventoryType.values()) {
typeItems.put(type, new ArrayList<>(storageItems));
}
c.announce(MaplePacketCreator.getStorage(npcId, slots, storageItems, meso));
}
public void sendStored(MapleClient c, MapleInventoryType type) {
c.announce(MaplePacketCreator.storeStorage(slots, type, typeItems.get(type)));
lock.lock();
try {
c.announce(MaplePacketCreator.storeStorage(slots, type, typeItems.get(type)));
} finally {
lock.unlock();
}
}
public void sendTakenOut(MapleClient c, MapleInventoryType type) {
c.announce(MaplePacketCreator.takeOutStorage(slots, type, typeItems.get(type)));
lock.lock();
try {
c.announce(MaplePacketCreator.takeOutStorage(slots, type, typeItems.get(type)));
} finally {
lock.unlock();
}
}
public int getMeso() {
@@ -279,6 +292,11 @@ public class MapleStorage {
}
public void close() {
typeItems.clear();
lock.lock();
try {
typeItems.clear();
} finally {
lock.unlock();
}
}
}
}

View File

@@ -167,7 +167,8 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
}
int price = (int)Math.min((long)pItem.getPrice() * quantity, Integer.MAX_VALUE);
if (c.getPlayer().getMeso() >= price) {
if (MapleInventoryManipulator.addFromDrop(c, newItem, false)) {
if (MapleInventoryManipulator.checkSpace(c, newItem.getItemId(), newItem.getQuantity(), newItem.getOwner())) {
MapleInventoryManipulator.addFromDrop(c, newItem, false);
c.getPlayer().gainMeso(-price, false);
synchronized (sold) {
@@ -196,7 +197,7 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
}
}
} else {
c.getPlayer().dropMessage(1, "Your inventory is full. Please clean a slot before buying this item.");
c.getPlayer().dropMessage(1, "Your inventory is full. Please clear a slot before buying this item.");
}
} else {
c.getPlayer().dropMessage(1, "You do not have enough mesos.");