Party Search + Conditional Buffs

Revised skillbook drops. New drop chances are related to the holder's level and boss flag.
Adjusted party bonus EXP gains. The level difference calculation now only takes into account party members that participated in the action.
Implemented Party Search in the source.
Refactored command classes initialization to take place when booting up the server.
Implemented support for conditional buffs (e.g. card buffs that takes place only in certain areas).
Implemented topological sorting when updating buffs to the player, this allows a better vision of buff streaks to the player (buff-applying the original way assumes stat override client-side, to circumvent that this algorithm makes up for the best-fit scenario).
Fixed Arans not taking Dojo's attack speed buff properly.
Fixed pets being improperly removed from the DB after performing certain inventory actions.
This commit is contained in:
ronancpl
2019-05-16 02:14:54 -03:00
parent 397e16bb85
commit bb80441af0
120 changed files with 68917 additions and 383 deletions
+19 -18
View File
@@ -30,37 +30,35 @@ public enum MapleBuffStat {
SHARP_EYES(0x20L),
MANA_REFLECTION(0x40L),
//ALWAYS_RIGHT(0X80L),
//------ bgn EDITED SLOT (was unused before) --------
MAP_PROTECTION(0x100000000000000L),
//------ end EDITED SLOT ----------------------------
SHADOW_CLAW(0x100L),
INFINITY(0x200L),
HOLY_SHIELD(0x400L),
HAMSTRING(0x800L),
BLIND(0x1000L),
CONCENTRATE(0x2000L),
HPREC(0x4000L),
PUPPET(0x4000L),
ECHO_OF_HERO(0x8000L),
MPREC(0x10000L),
MESO_UP_BY_ITEM(0x10000L),
GHOST_MORPH(0x20000L),
AURA(0x40000L),
CONFUSE(0x80000L),
ARIANT_PQ_SHIELD(0x40000L),
// ------ COUPON feature ------
COUPON_EXP1(0x100000L),
COUPON_EXP2(0x200000L),
COUPON_EXP3(0x400000L),
COUPON_EXP4(0x800000L),
COUPON_DRP1(0x1000000L),
COUPON_DRP2(0x2000000L),
COUPON_DRP3(0x4000000L),
COUPON_EXP3(0x400000L), COUPON_EXP4(0x400000L),
COUPON_DRP1(0x800000L),
COUPON_DRP2(0x1000000L), COUPON_DRP3(0x1000000L),
// ---- end COUPON feature ----
// ------ monster card buffs, thanks to Arnah (Vertisy) ------
ITEM_UP_BY_ITEM(0x100000L),
RESPECT_PIMMUNE(0x200000L),
RESPECT_MIMMUNE(0x400000L),
DEFENSE_ATT(0x800000L),
DEFENSE_STATE(0x1000000L),
HPREC(0x2000000L),
MPREC(0x4000000L),
BERSERK_FURY(0x8000000L),
DIVINE_BODY(0x10000000L),
SPARK(0x20000000L),
@@ -73,7 +71,6 @@ public enum MapleBuffStat {
ACC(0x1000000000L),
AVOID(0x2000000000L),
HANDS(0x4000000000L),
SHOWDASH(0x4000000000L),
SPEED(0x8000000000L),
JUMP(0x10000000000L),
MAGIC_GUARD(0x20000000000L),
@@ -96,11 +93,10 @@ public enum MapleBuffStat {
MESOUP(0x200000000000000L),
SHADOWPARTNER(0x400000000000000L),
PICKPOCKET(0x800000000000000L),
PUPPET(0x800000000000000L),
MESOGUARD(0x1000000000000000L),
EXP_INCREASE(0x2000000000000000L),
WEAKEN(0x4000000000000000L),
//THAT GAP
MAP_PROTECTION(0x8000000000000000L),
//all incorrect buffstats
SLOW(0x200000000L, true),
@@ -144,4 +140,9 @@ public enum MapleBuffStat {
public boolean isFirst() {
return isFirst;
}
@Override
public String toString() {
return name();
}
}
+293 -112
View File
@@ -44,6 +44,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
import java.util.Comparator;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.ScheduledFuture;
@@ -205,7 +206,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private transient int localstr, localdex, localluk, localint_, localmagic, localwatk;
private transient int equipmaxhp, equipmaxmp, equipstr, equipdex, equipluk, equipint_, equipmagic, equipwatk, localchairhp, localchairmp;
private int localchairrate;
private boolean hidden, equipchanged = true, canDoor = true, berserk, hasMerchant, hasSandboxItem = false, whiteChat = false;
private boolean hidden, equipchanged = true, canDoor = true, berserk, hasMerchant, hasSandboxItem = false, whiteChat = false, canRecvPartySearchInvite = true;
private boolean equippedMesoMagnet = false, equippedItemPouch = false, equippedPetItemIgnore = false;
private int linkedLevel = 0;
private String linkedName = null;
@@ -286,6 +287,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private Lock cpnLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_CPN);
private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
private Set<Integer> excludedItems = new LinkedHashSet<>();
private Set<Integer> disabledPartySearchInvites = new LinkedHashSet<>();
private static String[] ariantroomleader = new String[3];
private static int[] ariantroomslot = new int[3];
private long portaldelay = 0, lastcombo = 0;
@@ -484,6 +486,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public void setEnteredChannelWorld() {
awayFromWorld.set(false);
client.getChannelServer().removePlayerAway(id);
if (canRecvPartySearchInvite) {
this.getWorldServer().getPartySearchCoordinator().attachPlayer(this);
}
}
public void setAwayFromChannelWorld() {
@@ -504,6 +510,46 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
public void updatePartySearchAvailability(boolean psearchAvailable) {
if (psearchAvailable) {
if (canRecvPartySearchInvite && getParty() == null) {
this.getWorldServer().getPartySearchCoordinator().attachPlayer(this);
}
} else {
if (canRecvPartySearchInvite) {
this.getWorldServer().getPartySearchCoordinator().detachPlayer(this);
}
}
}
public boolean toggleRecvPartySearchInvite() {
canRecvPartySearchInvite = !canRecvPartySearchInvite;
if (canRecvPartySearchInvite) {
updatePartySearchAvailability(getParty() == null);
} else {
this.getWorldServer().getPartySearchCoordinator().detachPlayer(this);
}
return canRecvPartySearchInvite;
}
public boolean isRecvPartySearchInviteEnabled() {
return canRecvPartySearchInvite;
}
public void resetPartySearchInvite(int fromLeaderid) {
disabledPartySearchInvites.remove(fromLeaderid);
}
public void disablePartySearchInvite(int fromLeaderid) {
disabledPartySearchInvites.add(fromLeaderid);
}
public boolean hasDisabledPartySearchInvite(int fromLeaderid) {
return disabledPartySearchInvites.contains(fromLeaderid);
}
public void setSessionTransitionState() {
client.getSession().setAttribute(MapleClient.CLIENT_TRANSITION);
}
@@ -1047,7 +1093,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return;//the fuck you doing idiot!
}
this.job = newJob;
if (canRecvPartySearchInvite && getParty() == null) {
this.updatePartySearchAvailability(false);
this.job = newJob;
this.updatePartySearchAvailability(true);
} else {
this.job = newJob;
}
int spGain = 1;
if (GameConstants.hasSPTable(newJob)) {
@@ -3448,6 +3500,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
for(Entry<Integer, Map<MapleBuffStat, MapleBuffStatValueHolder>> bpl: buffEffects.entrySet()) {
MapleBuffStatValueHolder mbsvhi = bpl.getValue().get(mbs);
if(mbsvhi != null) {
if(!mbsvhi.effect.isActive(mapid)) {
continue;
}
if(mbsvhi.value > max.left) {
max = new Pair<>(mbsvhi.value, mbsvhi.effect.getStatups().size());
mbsvh = mbsvhi;
@@ -3477,6 +3533,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
effLock.lock();
chrLock.lock();
try {
System.out.println("-------------------");
System.out.println("CACHED BUFF COUNT: ");
for(Entry<MapleBuffStat, Byte> bpl : buffEffectsCount.entrySet()) {
System.out.println(bpl.getKey() + ": " + bpl.getValue());
}
System.out.println("-------------------");
System.out.println("CACHED BUFFS: ");
for(Entry<Integer, Map<MapleBuffStat, MapleBuffStatValueHolder>> bpl : buffEffects.entrySet()) {
@@ -3664,46 +3725,33 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
public void updateActiveEffects() {
chrLock.lock();
try {
effects.clear();
updateEffects(buffEffectsCount.keySet());
} finally {
chrLock.unlock();
}
}
private void updateEffects(Set<MapleBuffStat> removedStats) {
chrLock.lock();
try {
Map<Integer, Pair<MapleStatEffect, Long>> retrievedEffects = new LinkedHashMap<>();
Map<MapleBuffStat, Pair<Integer, Integer>> maxStatups = new LinkedHashMap<>();
for(Entry<Integer, Map<MapleBuffStat, MapleBuffStatValueHolder>> bel : buffEffects.entrySet()) {
for(Entry<MapleBuffStat, MapleBuffStatValueHolder> belv : bel.getValue().entrySet()) {
if(removedStats.contains(belv.getKey())) {
if(!retrievedEffects.containsKey(bel.getKey())) {
retrievedEffects.put(bel.getKey(), new Pair<>(belv.getValue().effect, belv.getValue().startTime));
}
Pair<Integer, Integer> thisStat = maxStatups.get(belv.getKey());
if(thisStat == null || belv.getValue().value > thisStat.getRight()) {
maxStatups.put(belv.getKey(), new Pair<>(bel.getKey(), belv.getValue().value));
}
}
}
}
Map<Integer, Pair<MapleStatEffect, Long>> bestEffects = new LinkedHashMap<>();
Set<MapleBuffStat> retrievedStats = new LinkedHashSet<>();
for(Entry<MapleBuffStat, Pair<Integer, Integer>> lmsee: maxStatups.entrySet()) {
if(isSingletonStatup(lmsee.getKey())) {
continue;
}
for (MapleBuffStat mbs : removedStats) {
fetchBestEffectFromItemEffectHolder(mbs);
Integer srcid = lmsee.getValue().getLeft();
if(!bestEffects.containsKey(srcid)) {
Pair<MapleStatEffect, Long> msel = retrievedEffects.get(srcid);
bestEffects.put(srcid, msel);
for(Pair<MapleBuffStat, Integer> mbsi : msel.getLeft().getStatups()) {
retrievedStats.add(mbsi.getLeft());
MapleBuffStatValueHolder mbsvh = effects.get(mbs);
if (mbsvh != null) {
for (Pair<MapleBuffStat, Integer> statup : mbsvh.effect.getStatups()) {
retrievedStats.add(statup.getLeft());
}
}
}
propagateBuffEffectUpdates(bestEffects, retrievedStats);
propagateBuffEffectUpdates(new LinkedHashMap<Integer, Pair<MapleStatEffect, Long>>(), retrievedStats, removedStats);
} finally {
chrLock.unlock();
}
@@ -3771,21 +3819,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
if (!overwrite) {
List<MapleBuffStat> cancelStats = new LinkedList<>();
chrLock.lock();
try {
for(Entry<MapleBuffStat, MapleBuffStatValueHolder> mbsl : buffstats.entrySet()) {
cancelStats.add(mbsl.getKey());
}
} finally {
chrLock.unlock();
}
for(MapleBuffStat mbs : cancelStats) {
removedStats.add(mbs);
}
cancelPlayerBuffs(cancelStats);
removedStats.addAll(buffstats.keySet());
}
return toCancel;
@@ -3909,7 +3943,152 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return extractedStatBuffs;
}
private void propagateBuffEffectUpdates(Map<Integer, Pair<MapleStatEffect, Long>> retrievedEffects, Set<MapleBuffStat> retrievedStats) {
private void cancelInactiveBuffStats(Set<MapleBuffStat> retrievedStats, Set<MapleBuffStat> removedStats) {
List<MapleBuffStat> inactiveStats = new LinkedList<>();
for (MapleBuffStat mbs : removedStats) {
if (!retrievedStats.contains(mbs)) {
inactiveStats.add(mbs);
}
}
if (!inactiveStats.isEmpty()) {
client.announce(MaplePacketCreator.cancelBuff(inactiveStats));
getMap().broadcastMessage(this, MaplePacketCreator.cancelForeignBuff(getId(), inactiveStats), false);
}
}
private static Map<MapleStatEffect, Integer> topologicalSortLeafStatCount(Map<MapleBuffStat, Stack<MapleStatEffect>> buffStack) {
Map<MapleStatEffect, Integer> leafBuffCount = new LinkedHashMap<>();
for (Entry<MapleBuffStat, Stack<MapleStatEffect>> e : buffStack.entrySet()) {
Stack<MapleStatEffect> mseStack = e.getValue();
if (mseStack.isEmpty()) {
continue;
}
MapleStatEffect mse = mseStack.peek();
Integer count = leafBuffCount.get(mse);
if (count == null) {
leafBuffCount.put(mse, 1);
} else {
leafBuffCount.put(mse, count + 1);
}
}
return leafBuffCount;
}
private static List<MapleStatEffect> topologicalSortRemoveLeafStats(Map<MapleStatEffect, Set<MapleBuffStat>> stackedBuffStats, Map<MapleBuffStat, Stack<MapleStatEffect>> buffStack, Map<MapleStatEffect, Integer> leafStatCount) {
List<MapleStatEffect> clearedStatEffects = new LinkedList<>();
Set<MapleBuffStat> clearedStats = new LinkedHashSet<>();
for (Entry<MapleStatEffect, Integer> e : leafStatCount.entrySet()) {
MapleStatEffect mse = e.getKey();
if (stackedBuffStats.get(mse).size() <= e.getValue()) {
clearedStatEffects.add(mse);
for (MapleBuffStat mbs : stackedBuffStats.get(mse)) {
clearedStats.add(mbs);
}
}
}
for (MapleBuffStat mbs : clearedStats) {
MapleStatEffect mse = buffStack.get(mbs).pop();
stackedBuffStats.get(mse).remove(mbs);
}
return clearedStatEffects;
}
private static void topologicalSortRebaseLeafStats(Map<MapleStatEffect, Set<MapleBuffStat>> stackedBuffStats, Map<MapleBuffStat, Stack<MapleStatEffect>> buffStack) {
for (Entry<MapleBuffStat, Stack<MapleStatEffect>> e : buffStack.entrySet()) {
Stack<MapleStatEffect> mseStack = e.getValue();
if (!mseStack.isEmpty()) {
MapleStatEffect mse = mseStack.pop();
stackedBuffStats.get(mse).remove(e.getKey());
}
}
}
private static List<MapleStatEffect> topologicalSortEffects(Map<MapleBuffStat, List<Pair<MapleStatEffect, Integer>>> buffEffects) {
Map<MapleStatEffect, Set<MapleBuffStat>> stackedBuffStats = new LinkedHashMap<>();
Map<MapleBuffStat, Stack<MapleStatEffect>> buffStack = new LinkedHashMap<>();
for (Entry<MapleBuffStat, List<Pair<MapleStatEffect, Integer>>> e : buffEffects.entrySet()) {
MapleBuffStat mbs = e.getKey();
Stack<MapleStatEffect> mbsStack = new Stack<>();
buffStack.put(mbs, mbsStack);
for (Pair<MapleStatEffect, Integer> emse : e.getValue()) {
MapleStatEffect mse = emse.getLeft();
mbsStack.push(mse);
Set<MapleBuffStat> mbsStats = stackedBuffStats.get(mse);
if (mbsStats == null) {
mbsStats = new LinkedHashSet<>();
stackedBuffStats.put(mse, mbsStats);
}
mbsStats.add(mbs);
}
}
List<MapleStatEffect> buffList = new LinkedList<>();
while (true) {
Map<MapleStatEffect, Integer> leafStatCount = topologicalSortLeafStatCount(buffStack);
if (leafStatCount.isEmpty()) break;
List<MapleStatEffect> clearedNodes = topologicalSortRemoveLeafStats(stackedBuffStats, buffStack, leafStatCount);
if (clearedNodes.isEmpty()) {
topologicalSortRebaseLeafStats(stackedBuffStats, buffStack);
} else {
buffList.addAll(clearedNodes);
}
}
return buffList;
}
private static List<MapleStatEffect> sortEffectsList(Map<MapleStatEffect, Integer> updateEffectsList) {
Map<MapleBuffStat, List<Pair<MapleStatEffect, Integer>>> buffEffects = new LinkedHashMap<>();
for (Entry<MapleStatEffect, Integer> p : updateEffectsList.entrySet()) {
MapleStatEffect mse = p.getKey();
for (Pair<MapleBuffStat, Integer> statup : mse.getStatups()) {
MapleBuffStat stat = statup.getLeft();
List<Pair<MapleStatEffect, Integer>> statBuffs = buffEffects.get(stat);
if (statBuffs == null) {
statBuffs = new ArrayList<>();
buffEffects.put(stat, statBuffs);
}
statBuffs.add(new Pair<>(mse, statup.getRight()));
}
}
Comparator cmp = new Comparator<Pair<MapleStatEffect, Integer>>() {
@Override
public int compare(Pair<MapleStatEffect, Integer> o1, Pair<MapleStatEffect, Integer> o2)
{
return o2.getRight().compareTo(o1.getRight());
}
};
for (Entry<MapleBuffStat, List<Pair<MapleStatEffect, Integer>>> statBuffs : buffEffects.entrySet()) {
Collections.sort(statBuffs.getValue(), cmp);
}
return topologicalSortEffects(buffEffects);
}
private void propagateBuffEffectUpdates(Map<Integer, Pair<MapleStatEffect, Long>> retrievedEffects, Set<MapleBuffStat> retrievedStats, Set<MapleBuffStat> removedStats) {
cancelInactiveBuffStats(retrievedStats, removedStats);
if (retrievedStats.isEmpty()) {
return;
}
@@ -3924,7 +4103,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
maxBuffValue.put(mbs, new Pair<>(Integer.MIN_VALUE, (MapleStatEffect) null));
}
Map<MapleStatEffect, Pair<Integer, Integer>> updateEffects = new LinkedHashMap<>();
Map<MapleStatEffect, Integer> updateEffects = new LinkedHashMap<>();
List<MapleStatEffect> recalcMseList = new LinkedList<>();
for(Entry<Integer, Pair<MapleStatEffect, Long>> re : retrievedEffects.entrySet()) {
@@ -3937,7 +4116,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
recalcMseList = new LinkedList<>();
for(MapleStatEffect mse : mseList) {
int mseAmount = 0;
int maxEffectiveStatup = Integer.MIN_VALUE;
for(Pair<MapleBuffStat, Integer> st : mse.getStatups()) {
MapleBuffStat mbs = st.getLeft();
@@ -3972,36 +4150,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
}
if(relevantStatup) {
mseAmount += st.getRight();
}
}
updateEffects.put(mse, new Pair<>(maxEffectiveStatup, mseAmount));
updateEffects.put(mse, maxEffectiveStatup);
}
} while(!recalcMseList.isEmpty());
List<Pair<MapleStatEffect, Pair<Integer, Integer>>> updateEffectsList = new ArrayList<>();
for(Entry<MapleStatEffect, Pair<Integer, Integer>> ue : updateEffects.entrySet()) {
updateEffectsList.add(new Pair<>(ue.getKey(), ue.getValue()));
}
Collections.sort(updateEffectsList, new Comparator<Pair<MapleStatEffect, Pair<Integer, Integer>>>() {
@Override
public int compare(Pair<MapleStatEffect, Pair<Integer, Integer>> o1, Pair<MapleStatEffect, Pair<Integer, Integer>> o2)
{
if(o1.getRight().getLeft().equals(o2.getRight().getLeft())) {
return o1.getRight().getRight().compareTo(o2.getRight().getRight());
} else {
return o1.getRight().getLeft().compareTo(o2.getRight().getLeft());
}
}
});
List<MapleStatEffect> updateEffectsList = sortEffectsList(updateEffects);
List<Pair<Integer, Pair<MapleStatEffect, Long>>> toUpdateEffects = new LinkedList<>();
for(Pair<MapleStatEffect, Pair<Integer, Integer>> msep : updateEffectsList) {
MapleStatEffect mse = msep.getLeft();
for(MapleStatEffect mse : updateEffectsList) {
toUpdateEffects.add(new Pair<>(mse.getBuffSourceId(), retrievedEffects.get(mse.getBuffSourceId())));
}
@@ -4010,9 +4168,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
Pair<MapleStatEffect, Long> msel = lmse.getRight();
for(Pair<MapleBuffStat, Integer> statup : getActiveStatupsFromSourceid(lmse.getLeft())) {
if(!isSingletonStatup(statup.getLeft())) {
activeStatups.add(statup);
}
activeStatups.add(statup);
}
msel.getLeft().updateBuffEffect(this, activeStatups, msel.getRight());
@@ -4061,6 +4217,17 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
private void addItemEffectHolderCount(MapleBuffStat stat) {
Byte val = buffEffectsCount.get(stat);
if (val != null) {
val = (byte) (val + 1);
} else {
val = (byte) 1;
}
buffEffectsCount.put(stat, val);
}
public void registerEffect(MapleStatEffect effect, long starttime, long expirationtime, boolean isSilent) {
if (effect.isDragonBlood()) {
prepareDragonBlood(effect);
@@ -4180,6 +4347,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
appliedStatups.put(ps.getLeft(), new MapleBuffStatValueHolder(effect, starttime, ps.getRight()));
}
boolean active = effect.isActive(mapid);
if(ServerConstants.USE_BUFF_MOST_SIGNIFICANT) {
toDeploy = new LinkedHashMap<>();
Map<Integer, Pair<MapleStatEffect, Long>> retrievedEffects = new LinkedHashMap<>();
@@ -4189,25 +4357,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
MapleBuffStatValueHolder mbsvh = effects.get(statup.getKey());
MapleBuffStatValueHolder statMbsvh = statup.getValue();
if(mbsvh == null || mbsvh.value < statMbsvh.value || (mbsvh.value == statMbsvh.value && mbsvh.effect.getStatups().size() <= statMbsvh.effect.getStatups().size())) {
toDeploy.put(statup.getKey(), statMbsvh);
} else {
if(!isSingletonStatup(statup.getKey())) {
retrievedEffects.put(mbsvh.effect.getBuffSourceId(), new Pair<>(mbsvh.effect, mbsvh.startTime));
for(Pair<MapleBuffStat, Integer> mbs : mbsvh.effect.getStatups()) {
retrievedStats.add(mbs.getLeft());
if(active) {
if(mbsvh == null || mbsvh.value < statMbsvh.value || (mbsvh.value == statMbsvh.value && mbsvh.effect.getStatups().size() <= statMbsvh.effect.getStatups().size())) {
toDeploy.put(statup.getKey(), statMbsvh);
} else {
if(!isSingletonStatup(statup.getKey())) {
for(Pair<MapleBuffStat, Integer> mbs : mbsvh.effect.getStatups()) {
retrievedStats.add(mbs.getLeft());
}
}
}
}
Byte val = buffEffectsCount.get(statup.getKey());
if (val != null) {
val = (byte) (val + 1);
} else {
val = (byte) 1;
}
buffEffectsCount.put(statup.getKey(), val);
addItemEffectHolderCount(statup.getKey());
}
if(!isSilent) {
@@ -4216,22 +4378,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
effects.put(statup.getKey(), statup.getValue());
}
retrievedEffects.put(sourceid, new Pair<>(effect, starttime));
propagateBuffEffectUpdates(retrievedEffects, retrievedStats);
if (active) {
retrievedEffects.put(sourceid, new Pair<>(effect, starttime));
}
propagateBuffEffectUpdates(retrievedEffects, retrievedStats, new LinkedHashSet<MapleBuffStat>());
}
} else {
for (Entry<MapleBuffStat, MapleBuffStatValueHolder> statup : appliedStatups.entrySet()) {
Byte val = buffEffectsCount.get(statup.getKey());
if (val != null) {
val = (byte) (val + 1);
} else {
val = (byte) 1;
}
buffEffectsCount.put(statup.getKey(), val);
addItemEffectHolderCount(statup.getKey());
}
toDeploy = appliedStatups;
toDeploy = (active ? appliedStatups : new LinkedHashMap<MapleBuffStat, MapleBuffStatValueHolder>());
}
addItemEffectHolder(sourceid, expirationtime, appliedStatups);
@@ -4607,6 +4765,24 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return w.getMesoRate() * w.getQuestRate();
}
public float getCardRate(int itemid) {
float rate = 100.0f;
if (itemid == 0) {
MapleStatEffect mseMeso = getBuffEffect(MapleBuffStat.MESO_UP_BY_ITEM);
if (mseMeso != null) {
rate += mseMeso.getCardRate(mapid, itemid);
}
} else {
MapleStatEffect mseItem = getBuffEffect(MapleBuffStat.ITEM_UP_BY_ITEM);
if (mseItem != null) {
rate += mseItem.getCardRate(mapid, itemid);
}
}
return rate / 100;
}
public int getFace() {
return face;
}
@@ -5169,6 +5345,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
this.gmLevel = Math.max(level, 0);
}
public void closePartySearchInteractions() {
this.getWorldServer().getPartySearchCoordinator().unregisterPartyLeader(this);
if (canRecvPartySearchInvite) {
this.getWorldServer().getPartySearchCoordinator().detachPlayer(this);
}
}
public void closePlayerInteractions() {
closeNpcShop();
closeTrade();
@@ -5570,8 +5753,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return vanquisherStage;
}
public Collection<MapleMapObject> getVisibleMapObjects() {
return Collections.unmodifiableCollection(visibleMapObjects);
public MapleMapObject[] getVisibleMapObjects() {
return visibleMapObjects.toArray(new MapleMapObject[visibleMapObjects.size()]);
}
public int getWorld() {
@@ -6717,6 +6900,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
int buddyCapacity = rs.getInt("buddyCapacity");
ret.buddylist = new BuddyList(buddyCapacity);
ret.lastExpGainTime = rs.getTimestamp("lastExpGainTime").getTime();
ret.canRecvPartySearchInvite = rs.getBoolean("partySearch");
ret.getInventory(MapleInventoryType.EQUIP).setSlotLimit(rs.getByte("equipslots"));
ret.getInventory(MapleInventoryType.USE).setSlotLimit(rs.getByte("useslots"));
@@ -7979,12 +8163,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
con.setAutoCommit(false);
PreparedStatement ps;
ps = con.prepareStatement("UPDATE characters SET level = ?, fame = ?, str = ?, dex = ?, luk = ?, `int` = ?, exp = ?, gachaexp = ?, hp = ?, mp = ?, maxhp = ?, maxmp = ?, sp = ?, ap = ?, gm = ?, skincolor = ?, gender = ?, job = ?, hair = ?, face = ?, map = ?, meso = ?, hpMpUsed = ?, spawnpoint = ?, party = ?, buddyCapacity = ?, messengerid = ?, messengerposition = ?, mountlevel = ?, mountexp = ?, mounttiredness= ?, equipslots = ?, useslots = ?, setupslots = ?, etcslots = ?, monsterbookcover = ?, vanquisherStage = ?, dojoPoints = ?, lastDojoStage = ?, finishedDojoTutorial = ?, vanquisherKills = ?, matchcardwins = ?, matchcardlosses = ?, matchcardties = ?, omokwins = ?, omoklosses = ?, omokties = ?, dataString = ?, fquest = ?, jailexpire = ?, partnerId = ?, marriageItemId = ?, lastExpGainTime = ?, ariantPoints = ? WHERE id = ?", Statement.RETURN_GENERATED_KEYS);
if (gmLevel < 1 && level > 199) {
ps.setInt(1, isCygnus() ? 120 : 200);
} else {
ps.setInt(1, level);
}
ps = con.prepareStatement("UPDATE characters SET level = ?, fame = ?, str = ?, dex = ?, luk = ?, `int` = ?, exp = ?, gachaexp = ?, hp = ?, mp = ?, maxhp = ?, maxmp = ?, sp = ?, ap = ?, gm = ?, skincolor = ?, gender = ?, job = ?, hair = ?, face = ?, map = ?, meso = ?, hpMpUsed = ?, spawnpoint = ?, party = ?, buddyCapacity = ?, messengerid = ?, messengerposition = ?, mountlevel = ?, mountexp = ?, mounttiredness= ?, equipslots = ?, useslots = ?, setupslots = ?, etcslots = ?, monsterbookcover = ?, vanquisherStage = ?, dojoPoints = ?, lastDojoStage = ?, finishedDojoTutorial = ?, vanquisherKills = ?, matchcardwins = ?, matchcardlosses = ?, matchcardties = ?, omokwins = ?, omoklosses = ?, omokties = ?, dataString = ?, fquest = ?, jailexpire = ?, partnerId = ?, marriageItemId = ?, lastExpGainTime = ?, ariantPoints = ?, partySearch = ? WHERE id = ?", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, level); // thanks CanIGetaPR for noticing an unnecessary "level" limitation when persisting DB data
ps.setInt(2, fame);
effLock.lock();
@@ -8094,7 +8274,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ps.setInt(52, marriageItemid);
ps.setTimestamp(53, new Timestamp(lastExpGainTime));
ps.setInt(54, ariantPoints);
ps.setInt(55, id);
ps.setBoolean(55, canRecvPartySearchInvite);
ps.setInt(56, id);
int updateRows = ps.executeUpdate();
ps.close();
+2
View File
@@ -888,6 +888,7 @@ public class MapleClient {
player.cancelAllBuffs(true);
player.closePlayerInteractions();
player.closePartySearchInteractions();
if (!serverTransition) { // thanks MedicOP for detecting an issue with party leader change on changing channels
removePartyPlayer(wserv);
@@ -1463,6 +1464,7 @@ public class MapleClient {
}
player.closePlayerInteractions();
player.closePartySearchInteractions();
player.unregisterChairBuff();
server.getPlayerBuffStorage().addBuffsToStorage(player.getId(), player.getAllBuffs());
-5
View File
@@ -114,11 +114,6 @@ public enum MapleJob {
return BEGINNER;
}
}
public boolean isBeginner(MapleJob beginners) {
return MAGICIAN == beginners || WARRIOR == beginners || THIEF == beginners || PIRATE == beginners || BOWMAN == beginners || ARAN1 == beginners || THUNDERBREAKER1 == beginners
|| DAWNWARRIOR1 == beginners || NIGHTWALKER1 == beginners || BLAZEWIZARD1 == beginners;
}
public boolean isA(MapleJob basejob) { // thanks Steve (kaito1410) for pointing out an improvement here
int basebranch = basejob.getId() / 10;
+13 -9
View File
@@ -9,6 +9,7 @@ import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import server.ThreadManager;
public class IdCommand extends Command {
{
@@ -34,7 +35,7 @@ public class IdCommand extends Command {
return;
}
final String queryItem = joinStringArr(Arrays.copyOfRange(params, 1, params.length), " ");
player.yellowMessage("Querying for entry... May take some time... Please try to refine your search");
player.yellowMessage("Querying for entry... May take some time... Please try to refine your search.");
Runnable queryRunnable = new Runnable() {
@Override
public void run() {
@@ -42,28 +43,31 @@ public class IdCommand extends Command {
populateIdMap(params[0].toLowerCase());
Map<String, String> resultList = fetchResults(itemMap.get(params[0]), queryItem);
StringBuilder sb = new StringBuilder();
if (resultList.size() > 0) {
int count = 0;
for (Map.Entry<String, String> entry: resultList.entrySet()) {
player.yellowMessage(String.format("Id for %s is: %s", entry.getKey(), entry.getValue()));
sb.append(String.format("Id for %s is: #b%s#k", entry.getKey(), entry.getValue()) + "\r\n");
if (++count > 100) {
break;
}
}
player.yellowMessage(String.format("Results found: %d | Returned: %d/100 | Refine search query to improve time.", resultList.size(), count - 1));
sb.append(String.format("Results found: #r%d#k | Returned: #b%d#k/100 | Refine search query to improve time.", resultList.size(), count) + "\r\n");
player.getClient().getAbstractPlayerInteraction().npcTalk(9010000, sb.toString());
} else {
player.yellowMessage(String.format("Id not found for item: %s, of type: %s", queryItem, params[0]));
player.yellowMessage(String.format("Id not found for item: %s, of type: %s.", queryItem, params[0]));
}
} catch (IdTypeNotSupportedException e) {
player.yellowMessage("Your query type is not supported");
player.yellowMessage("Your query type is not supported.");
} catch (IOException e) {
player.yellowMessage("Error reading file, please contact your administrator");
player.yellowMessage("Error reading file, please contact your administrator.");
}
}
};
Thread thread = new Thread(queryRunnable);
thread.start();
ThreadManager.getInstance().newTask(queryRunnable);
}
private void populateIdMap(String type) throws IdTypeNotSupportedException, IOException {
@@ -39,10 +39,9 @@ import tools.MaplePacketCreator;
import java.awt.*;
import java.util.Arrays;
import java.util.List;
import tools.packets.Wedding;
public class DebugCommand extends Command {
private final static String debugTypes[] = {"monster", "packet", "portal", "spawnpoint", "pos", "map", "mobsp", "event", "areas", "reactors", "servercoupons", "playercoupons", "timer", "marriage", ""};
private final static String debugTypes[] = {"monster", "packet", "portal", "spawnpoint", "pos", "map", "mobsp", "event", "areas", "reactors", "servercoupons", "playercoupons", "timer", "marriage", "buff", ""};
{
setDescription("");
@@ -158,7 +157,10 @@ public class DebugCommand extends Command {
case "marriage":
c.getChannelServer().debugMarriageStatus();
break;
case "buff":
c.getPlayer().debugListAllBuffs();
break;
}
}
}
+59
View File
@@ -98,6 +98,65 @@ public class MaplePet extends Item {
}
}
private static void unreferenceMissingPetsFromInventoryDb() {
PreparedStatement ps = null;
Connection con = null;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("UPDATE inventoryitems SET petid = -1, expiration = 0 WHERE petid != -1 AND petid NOT IN (SELECT petid FROM pets)");
ps.executeUpdate();
ps.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
} finally {
try {
if(ps != null && !ps.isClosed()) {
ps.close();
}
if(con != null && !con.isClosed()) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private static void deleteMissingPetsFromDb() {
PreparedStatement ps = null;
Connection con = null;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("DELETE FROM pets WHERE petid NOT IN (SELECT petid FROM inventoryitems WHERE petid != -1)");
ps.executeUpdate();
ps.close();
con.close();
} catch(SQLException ex) {
ex.printStackTrace();
} finally {
try {
if(ps != null && !ps.isClosed()) {
ps.close();
}
if(con != null && !con.isClosed()) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void clearMissingPetsFromDb() {
unreferenceMissingPetsFromInventoryDb();
deleteMissingPetsFromDb();
}
public static void deleteFromDb(MapleCharacter owner, int petid) {
try {
Connection con = DatabaseConnection.getConnection();
@@ -439,7 +439,7 @@ public class MapleInventoryManipulator {
announceModifyInventory(c, item, fromDrop, allowZero);
}
MaplePet.deleteFromDb(chr, petid);
// thanks Robin Schulz for noticing pet issues when moving pets out of inventory
} else {
inv.removeItem(slot, quantity, allowZero);
if(type != MapleInventoryType.CANHOLD) {