Alliances & Pet autopot improvement + Crafters patch

Improved Alliance invitations now using "invite popups" just like buddy, party and guild invites.
Pet autopot now properly uses up pots from the inventory, fetching from other inventory slots when one place has been completely used up but the "stop criteria" hasn't been fulfilled yet.
Pet autopot now properly detects pots with healing factor defined by the character's pool.
Fixed old exploit with mineral/jewel crafters.
Patched Doorway's questlines.
This commit is contained in:
ronancpl
2018-01-16 15:34:52 -02:00
parent 346d39c03a
commit f74dfbb46a
40 changed files with 619 additions and 207 deletions

View File

@@ -345,7 +345,7 @@ public class Commands {
public static boolean executeHeavenMsCommandLv0(Channel cserv, Server srv, MapleClient c, String[] sub) { //Player
MapleCharacter player = c.getPlayer();
switch(sub[0]) {
switch(sub[0]) {
case "help":
case "commands":
case "playercommands":

View File

@@ -121,13 +121,14 @@ public class Item implements Comparable<Item> {
this.petid = id;
}
@Override
public int compareTo(Item other) {
if (this.id < other.getItemId()) {
return -1;
} else if (this.id > other.getItemId()) {
return 1;
}
return 0;
return 0;
}
@Override

View File

@@ -24,8 +24,10 @@ package client.inventory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Map;
@@ -178,9 +180,36 @@ public class MapleInventory implements Iterable<Item> {
ret.add(item);
}
}
if (ret.size() > 1) {
Collections.sort(ret);
Collections.sort(ret, new Comparator<Item>() {
@Override
public int compare(Item i1, Item i2) {
return i1.getPosition() - i2.getPosition();
}
});
}
return ret;
}
public List<Item> linkedListById(int itemId) {
List<Item> ret = new LinkedList<>();
for (Item item : list()) {
if (item.getItemId() == itemId) {
ret.add(item);
}
}
if (ret.size() > 1) {
Collections.sort(ret, new Comparator<Item>() {
@Override
public int compare(Item i1, Item i2) {
return i1.getPosition() - i2.getPosition();
}
});
}
return ret;
}

View File

@@ -35,89 +35,111 @@ import tools.data.output.MaplePacketLittleEndianWriter;
/**
*
* @author XoticStory
* @author XoticStory, Ronan
*/
public final class AllianceOperationHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleAlliance alliance = null;
if (c.getPlayer().getGuild() != null && c.getPlayer().getGuild().getAllianceId() > 0) {
alliance = c.getPlayer().getAlliance();
}
if (alliance == null) {
c.announce(MaplePacketCreator.enableActions());
return;
} else if (c.getPlayer().getMGC().getAllianceRank() > 2 || !alliance.getGuilds().contains(c.getPlayer().getGuildId())) {
MapleCharacter chr = c.getPlayer();
if (chr.getGuild() == null) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if (chr.getGuild().getAllianceId() > 0) {
alliance = chr.getAlliance();
}
byte b = slea.readByte();
if (alliance == null) {
if (b != 4) {
c.announce(MaplePacketCreator.enableActions());
return;
}
} else {
if (b == 4) {
chr.dropMessage("Your guild is already registered on a Guild Alliance.");
c.announce(MaplePacketCreator.enableActions());
return;
}
if (chr.getMGC().getAllianceRank() > 2 || !alliance.getGuilds().contains(chr.getGuildId())) {
c.announce(MaplePacketCreator.enableActions());
return;
}
}
// "alliance" is only null at case 0x04
switch (b) {
case 0x01:
Server.getInstance().allianceMessage(alliance.getId(), sendShowInfo(c.getPlayer().getGuild().getAllianceId(), c.getPlayer().getId()), -1, -1);
Server.getInstance().allianceMessage(alliance.getId(), sendShowInfo(chr.getGuild().getAllianceId(), chr.getId()), -1, -1);
break;
case 0x02: { // Leave Alliance
if (c.getPlayer().getGuild().getAllianceId() == 0 || c.getPlayer().getGuildId() < 1 || c.getPlayer().getGuildRank() != 1) {
if (chr.getGuild().getAllianceId() == 0 || chr.getGuildId() < 1 || chr.getGuildRank() != 1) {
return;
}
MapleAlliance.removeGuildFromAlliance(c.getPlayer().getGuild().getAllianceId(), c.getPlayer().getGuildId(), c.getPlayer().getWorld());
MapleAlliance.removeGuildFromAlliance(chr.getGuild().getAllianceId(), chr.getGuildId(), chr.getWorld());
break;
}
case 0x03: // send alliance invite... or at least it would be this way if i could find the right way to call it!
case 0x03: // Send Invite
String guildName = slea.readMapleAsciiString();
if(alliance.getGuilds().size() == alliance.getCapacity()) {
c.getPlayer().dropMessage("Your alliance can not comport any more guild at the moment.");
chr.dropMessage("Your alliance cannot comport any more guilds at the moment.");
} else {
MapleGuild mg = Server.getInstance().getGuildByName(guildName);
if(mg == null) {
c.getPlayer().dropMessage("The entered guild does not exist.");
chr.dropMessage("The entered guild does not exist.");
}
else {
MapleCharacter victim = mg.getMGC(mg.getLeaderId()).getCharacter();
if (victim == null) {
c.getPlayer().dropMessage("The master of the guild that you offered an invitation is currently not online.");
chr.dropMessage("The master of the guild that you offered an invitation is currently not online.");
} else {
// this doesn't seem to work...
//Server.getInstance().allianceMessage(alliance.getId(), sendInvitation(c.getPlayer().getGuild().getAllianceId(), victim.getId(), guildName), -1, -1);
//victim.getClient().announce(sendInvitation(c.getPlayer().getGuild().getAllianceId(), c.getPlayer().getId(), guildName));
if(!c.getPlayer().isPartyMember(victim)) {
c.getPlayer().dropMessage("The master of the guild that you offered a invitation must be in the same party as yours.");
}
else {
int guildid = victim.getGuildId();
Server.getInstance().addGuildtoAlliance(alliance.getId(), guildid);
Server.getInstance().resetAllianceGuildPlayersRank(guildid);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.addGuildToAlliance(alliance, guildid, c), -1, -1);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.updateAllianceInfo(alliance, c), -1, -1);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.allianceNotice(alliance.getId(), alliance.getNotice()), -1, -1);
victim.getGuild().dropMessage("Your guild has joined the [" + alliance.getName() + "] union.");
}
victim.getClient().announce(MaplePacketCreator.sendAllianceInvitation(alliance.getId(), chr));
}
}
}
break;
case 0x04: {
int guildid = slea.readInt();
// slea.readMapleAsciiString();//guild name
if (c.getPlayer().getGuild().getAllianceId() != 0 || c.getPlayer().getGuildRank() != 1 || c.getPlayer().getGuildId() < 1) {
case 0x04: { // Accept Invite
if (chr.getGuild().getAllianceId() != 0 || chr.getGuildRank() != 1 || chr.getGuildId() < 1) {
return;
}
Server.getInstance().allianceMessage(alliance.getId(), sendChangeGuild(guildid, c.getPlayer().getId(), c.getPlayer().getGuildId(), 0), -1, -1);
int allianceid = slea.readInt();
//slea.readMapleAsciiString(); //recruiter's guild name
alliance = Server.getInstance().getAlliance(allianceid);
if (alliance == null) {
return;
}
int guildid = chr.getGuildId();
Server.getInstance().addGuildtoAlliance(alliance.getId(), guildid);
Server.getInstance().resetAllianceGuildPlayersRank(guildid);
chr.getMGC().setAllianceRank(2);
Server.getInstance().getGuild(chr.getGuildId()).getMGC(chr.getId()).setAllianceRank(2);
chr.saveGuildStatus();
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.addGuildToAlliance(alliance, guildid, c), -1, -1);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.updateAllianceInfo(alliance, c), -1, -1);
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.allianceNotice(alliance.getId(), alliance.getNotice()), -1, -1);
chr.getGuild().dropMessage("Your guild has joined the [" + alliance.getName() + "] union.");
break;
}
case 0x06: { // Expel Guild
int guildid = slea.readInt();
int allianceid = slea.readInt();
if (c.getPlayer().getGuild().getAllianceId() == 0 || c.getPlayer().getGuild().getAllianceId() != allianceid) {
if (chr.getGuild().getAllianceId() == 0 || chr.getGuild().getAllianceId() != allianceid) {
return;
}
@@ -132,13 +154,16 @@ public final class AllianceOperationHandler extends AbstractMaplePacketHandler {
break;
}
case 0x07: { // Change Alliance Leader
if (c.getPlayer().getGuild().getAllianceId() == 0 || c.getPlayer().getGuildId() < 1) {
if (chr.getGuild().getAllianceId() == 0 || chr.getGuildId() < 1) {
return;
}
int victimid = slea.readInt();
MapleCharacter player = Server.getInstance().getWorld(c.getWorld()).getPlayerStorage().getCharacterById(victimid);
if (player.getAllianceRank() != 2) {
return;
}
//Server.getInstance().allianceMessage(alliance.getId(), sendChangeLeader(c.getPlayer().getGuild().getAllianceId(), c.getPlayer().getId(), slea.readInt()), -1, -1);
//Server.getInstance().allianceMessage(alliance.getId(), sendChangeLeader(chr.getGuild().getAllianceId(), chr.getId(), slea.readInt()), -1, -1);
changeLeaderAllianceRank(alliance, player);
break;
}
@@ -154,7 +179,7 @@ public final class AllianceOperationHandler extends AbstractMaplePacketHandler {
int int1 = slea.readInt();
byte byte1 = slea.readByte();
//Server.getInstance().allianceMessage(alliance.getId(), sendChangeRank(c.getPlayer().getGuild().getAllianceId(), c.getPlayer().getId(), int1, byte1), -1, -1);
//Server.getInstance().allianceMessage(alliance.getId(), sendChangeRank(chr.getGuild().getAllianceId(), chr.getId(), int1, byte1), -1, -1);
MapleCharacter player = Server.getInstance().getWorld(c.getWorld()).getPlayerStorage().getCharacterById(int1);
changePlayerAllianceRank(alliance, player, (byte1 > 0));
@@ -168,7 +193,7 @@ public final class AllianceOperationHandler extends AbstractMaplePacketHandler {
alliance.dropMessage(5, "* Alliance Notice : " + notice);
break;
default:
c.getPlayer().dropMessage("Feature not available");
chr.dropMessage("Feature not available");
}
alliance.saveToDB();
@@ -195,7 +220,7 @@ public final class AllianceOperationHandler extends AbstractMaplePacketHandler {
chr.saveGuildStatus();
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.getGuildAlliances(alliance, chr.getWorld()), -1, -1);
alliance.dropMessage("'" + chr.getName() + "' has been reassigned as '" + alliance.getRankTitle(newRank) + "' in this Alliance.");
alliance.dropMessage("'" + chr.getName() + "' has been reassigned to '" + alliance.getRankTitle(newRank) + "' in this Alliance.");
}
private static byte[] sendShowInfo(int allianceid, int playerid) {

View File

@@ -29,15 +29,27 @@ import net.AbstractMaplePacketHandler;
import server.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
import server.MapleStatEffect;
import tools.Pair;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import constants.ServerConstants;
import java.util.List;
/**
*
* @author Ronan (multi-pot consumption feature)
*/
public final class PetAutoPotHandler extends AbstractMaplePacketHandler {
short slot;
int itemId;
Item toUse;
List<Item> toUseList;
boolean hasHpGain;
boolean hasMpGain;
short maxHp;
short maxMp;
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (!c.getPlayer().isAlive()) {
@@ -45,45 +57,103 @@ public final class PetAutoPotHandler extends AbstractMaplePacketHandler {
return;
}
MapleCharacter chr = c.getPlayer();
short maxHp = 0, maxMp = 0;
if(ServerConstants.USE_EQUIPS_ON_AUTOPOT) {
for(Item i : c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).list()) {
Equip e = (Equip) i;
maxHp += e.getHp();
maxMp += e.getMp();
}
}
maxHp = (short) Math.min(chr.getMaxHp() + maxHp, 30000);
maxMp = (short) Math.min(chr.getMaxMp() + maxMp, 30000);
slea.readByte();
slea.readLong();
slea.readInt();
short slot = slea.readShort();
int itemId = slea.readInt();
Item toUse = chr.getInventory(MapleInventoryType.USE).getItem(slot);
slot = slea.readShort();
itemId = slea.readInt();
MapleCharacter chr = c.getPlayer();
toUse = chr.getInventory(MapleInventoryType.USE).getItem(slot);
if(toUse != null) {
MapleStatEffect stat = MapleItemInformationProvider.getInstance().getItemEffect(toUse.getItemId());
if (toUse.getQuantity() <= 0 || toUse.getItemId() != itemId) {
if (toUse.getItemId() != itemId) {
c.announce(MaplePacketCreator.enableActions());
return;
}
do {
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, slot, (short) 1, false);
stat.applyTo(chr);
toUseList = null;
// from now on, toUse becomes the "cursor" for the current pot being used
if(toUse.getQuantity() <= 0) {
if(!cursorOnNextAvailablePot(chr)) {
c.announce(MaplePacketCreator.enableActions());
return;
}
}
MapleStatEffect stat = MapleItemInformationProvider.getInstance().getItemEffect(toUse.getItemId());
hasHpGain = stat.getHp() > 0 || stat.getHpRate() > 0.0;
hasMpGain = stat.getMp() > 0 || stat.getMpRate() > 0.0;
// contabilize the HP and MP gains from equipments on one's effective MaxHP/MaxMP
Pair<Short, Short> maxHpMp = calcEffectivePool(chr);
maxHp = maxHpMp.left;
maxMp = maxHpMp.right;
while(true) {
do {
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, slot, (short) 1, false);
stat.applyTo(chr);
//System.out.println();
//System.out.println("hp: " + stat.getHp() + " player hp " + c.getPlayer().getHp() + " maxhp " + maxHp);
//System.out.println("mp: " + stat.getMp() + " player mp " + c.getPlayer().getMp() + " maxmp " + maxMp);
//System.out.println("redo? " + (((stat.getHp() > 0 && c.getPlayer().getHp() < ServerConstants.PET_AUTOHP_RATIO * maxHp) || (stat.getMp() > 0 && c.getPlayer().getMp() < ServerConstants.PET_AUTOMP_RATIO * maxMp)) && toUse.getQuantity() > 0));
} while(((stat.getHp() > 0 && chr.getHp() < ServerConstants.PET_AUTOHP_RATIO * maxHp) || (stat.getMp() > 0 && chr.getMp() < ServerConstants.PET_AUTOMP_RATIO * maxMp)) && toUse.getQuantity() > 0);
//System.out.println();
//System.out.println("hp: " + hasHpGain + " player hp " + chr.getHp() + " maxhp " + maxHp);
//System.out.println("mp: " + hasMpGain + " player mp " + chr.getMp() + " maxmp " + maxMp);
//System.out.println("redo? " + (shouldReusePot(chr) && toUse.getQuantity() > 0));
} while(shouldReusePot(chr) && toUse.getQuantity() > 0);
if(toUse.getQuantity() == 0 && shouldReusePot(chr)) {
// depleted out the current slot, fetch for more
if(!cursorOnNextAvailablePot(chr)) {
break; // no more pots available
}
} else {
break; // gracefully finished it's job, quit the loop
}
}
}
}
private boolean cursorOnNextAvailablePot(MapleCharacter chr) {
if(toUseList == null) {
toUseList = chr.getInventory(MapleInventoryType.USE).linkedListById(itemId);
}
toUse = null;
while(!toUseList.isEmpty()) {
Item it = toUseList.remove(0);
if(it.getQuantity() > 0) {
toUse = it;
slot = it.getPosition();
return true;
}
}
return false;
}
private Pair<Short, Short> calcEffectivePool(MapleCharacter chr) {
short hp = 0, mp = 0;
if(ServerConstants.USE_EQUIPS_ON_AUTOPOT) {
for(Item i : chr.getInventory(MapleInventoryType.EQUIPPED).list()) {
Equip e = (Equip) i;
hp += e.getHp();
mp += e.getMp();
}
}
hp = (short) Math.min(chr.getMaxHp() + hp, 30000);
mp = (short) Math.min(chr.getMaxMp() + mp, 30000);
return new Pair<>(hp, mp);
}
private boolean shouldReusePot(MapleCharacter chr) {
return (hasHpGain && chr.getHp() < ServerConstants.PET_AUTOHP_RATIO * maxHp) || (hasMpGain && chr.getMp() < ServerConstants.PET_AUTOMP_RATIO * maxMp);
}
}

View File

@@ -130,7 +130,6 @@ public class MapleAlliance {
Server.getInstance().addAlliance(id, alliance);
System.out.println("\n\n\n\n----");
Server.getInstance().allianceMessage(id, MaplePacketCreator.updateAllianceInfo(alliance, guildMasters.get(0).getClient()), -1, -1);
} catch (Exception e) {
e.printStackTrace();

View File

@@ -1593,6 +1593,14 @@ public class MapleStatEffect {
return mp;
}
public double getHpRate() {
return hpR;
}
public double getMpRate() {
return mpR;
}
public byte getHpR() {
return mhpR;
}

View File

@@ -69,6 +69,7 @@ public class MapleFoothold implements Comparable<MapleFoothold> {
return (slope * x) + intercept;
}
@Override
public int compareTo(MapleFoothold o) {
MapleFoothold other = o;
if (p2.y < other.getY1()) {

View File

@@ -6343,7 +6343,17 @@ public class MaplePacketCreator {
mplew.writeInt(alliance);
return mplew.getPacket();
}
public static byte[] sendAllianceInvitation(int allianceid, MapleCharacter chr) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
mplew.write(0x03);
mplew.writeInt(allianceid);
mplew.writeMapleAsciiString(chr.getName());
mplew.writeShort(0);
return mplew.getPacket();
}
public static byte[] sendMesoLimit() {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.TRADE_MONEY_LIMIT.getValue()); //Players under level 15 can only trade 1m per day