Heal & Summons atk limit + Skills on change job + Java8 scripting fix
Adjusted reactor drops, now performing spray-like for any reactor. Revised usage of synchronized statements in several methods in the source. Fixed a quest from the Aran questline using "password" system unpredictedly. Fixed column name in table "reports". Fixed commands "startquest" and "completequest" not using the quest's NPC in the talk window. Fixed HP regen bonuses such as sauna robes and from Endure skill, when applied in maps with improved regen, leading to false-positives (with the heal on the player). Fixed a recent typo on a property from HenesysPQ. Fixed "Combat Step" effect showing twice for other players. Fixed type-cast issues within some script-hubbing methods in some Java classes. Reactivated an unused flag that ignores level difference when applying EXP gains to party players. Fixed Gaviota not disappearing after attack, as defined in the description of the skill. Fixed CPQ1 field 3 & 4 not allowing players to use summons/protectors. Fixed exped leaders still receiving exped creation packets even though it was dismissed due to failure on starting (daily entry limit, other fail cases). Fixed a locking issue that would show up due to a infinite loop case within the procedure that makes disappear items immediately if there were already many items on map. Fixed several summon skills not using buff icons. Fixed max damage calculation for summons getting extremely low values when either a player doesn't equip a weapon or attack value is too low. Fixed explosive loots not taking effect at all, although loot drop-types were already implemented. Fixed NPE cases when trying to update position of summons/dragons server-side. Reviewed reactor reset of reactors that disappears for a while. They are now supposed to return immediately once issued a reset.
This commit is contained in:
@@ -460,6 +460,7 @@ public final class Channel {
|
||||
}
|
||||
|
||||
expeditions.put(exped.getType(), exped);
|
||||
exped.beginRegistration(); // thanks Conrad for noticing leader still receiving packets on failure-to-register cases
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,8 +134,9 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void applyAttack(AttackInfo attack, final MapleCharacter player, int attackCount) {
|
||||
if (player.getMap().isOwnershipRestricted(player)) {
|
||||
protected void applyAttack(AttackInfo attack, final MapleCharacter player, int attackCount) {
|
||||
final MapleMap map = player.getMap();
|
||||
if (map.isOwnershipRestricted(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -150,7 +151,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
theSkill = SkillFactory.getSkill(GameConstants.getHiddenSkill(attack.skill)); //returns back the skill id if its not a hidden skill so we are gucci
|
||||
attackEffect = attack.getAttackEffect(player, theSkill);
|
||||
if (attackEffect == null) {
|
||||
player.getClient().announce(MaplePacketCreator.enableActions());
|
||||
player.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -176,7 +177,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
}
|
||||
}
|
||||
} else {
|
||||
player.getClient().announce(MaplePacketCreator.enableActions());
|
||||
player.announce(MaplePacketCreator.enableActions());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +196,6 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
}*/
|
||||
|
||||
int totDamage = 0;
|
||||
final MapleMap map = player.getMap();
|
||||
|
||||
if (attack.skill == ChiefBandit.MESO_EXPLOSION) {
|
||||
int delay = 0;
|
||||
@@ -308,7 +308,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
player.getMap().spawnMesoDrop(Math.min((int) Math.max(((double) eachdf / (double) 20000) * (double) maxmeso, (double) 1), maxmeso), new Point((int) (monster.getPosition().getX() + Randomizer.nextInt(100) - 50), (int) (monster.getPosition().getY())), monster, player, true, (byte) 2);
|
||||
map.spawnMesoDrop(Math.min((int) Math.max(((double) eachdf / (double) 20000) * (double) maxmeso, (double) 1), maxmeso), new Point((int) (monster.getPosition().getX() + Randomizer.nextInt(100) - 50), (int) (monster.getPosition().getY())), monster, player, true, (byte) 2);
|
||||
}
|
||||
}, delay);
|
||||
delay += 100;
|
||||
@@ -333,7 +333,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
List<MonsterDropEntry> toSteal = new ArrayList<>();
|
||||
toSteal.add(mi.retrieveDrop(monster.getId()).get(i));
|
||||
|
||||
player.getMap().dropItemsFromMonster(toSteal, player, monster);
|
||||
map.dropItemsFromMonster(toSteal, player, monster);
|
||||
monster.addStolen(toSteal.get(0).itemId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.autoban.AutobanFactory;
|
||||
import client.autoban.AutobanManager;
|
||||
import constants.GameConstants;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import server.maps.MapleMapFactory;
|
||||
@@ -46,7 +47,7 @@ public final class HealOvertimeHandler extends AbstractMaplePacketHandler {
|
||||
abm.setTimestamp(8, timestamp, 28); // thanks Vcoc & Thora for pointing out d/c happening here
|
||||
if ((abm.getLastSpam(0) + 1500) > timestamp) AutobanFactory.FAST_HP_HEALING.addPoint(abm, "Fast hp healing");
|
||||
|
||||
int abHeal = 120 + (int)(20 * MapleMapFactory.getMapRecoveryRate(chr.getMapId())); // Sleepywood sauna and showa spa...
|
||||
int abHeal = (int)(77 * MapleMapFactory.getMapRecoveryRate(chr.getMapId()) * 1.5); // thanks Ari for noticing players not getting healed in sauna in certain cases
|
||||
if (healHP > abHeal) {
|
||||
AutobanFactory.HIGH_HP_HEALING.autoban(chr, "Healing: " + healHP + "; Max is " + abHeal + ".");
|
||||
return;
|
||||
|
||||
@@ -37,14 +37,16 @@ public class MoveDragonHandler extends AbstractMovementPacketHandler {
|
||||
final Point startPos = new Point(slea.readShort(), slea.readShort());
|
||||
long movementDataStart = slea.getPosition();
|
||||
final MapleDragon dragon = chr.getDragon();
|
||||
updatePosition(slea, dragon, 0);
|
||||
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
|
||||
if (dragon != null && movementDataLength > 0) {
|
||||
slea.seek(movementDataStart);
|
||||
if (chr.isHidden()) {
|
||||
chr.getMap().broadcastGMMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, slea, movementDataLength));
|
||||
} else {
|
||||
chr.getMap().broadcastMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, slea, movementDataLength), dragon.getPosition());
|
||||
if (dragon != null) {
|
||||
updatePosition(slea, dragon, 0);
|
||||
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
|
||||
if (movementDataLength > 0) {
|
||||
slea.seek(movementDataStart);
|
||||
if (chr.isHidden()) {
|
||||
chr.getMap().broadcastGMMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, slea, movementDataLength));
|
||||
} else {
|
||||
chr.getMap().broadcastMessage(chr, MaplePacketCreator.moveDragon(dragon, startPos, slea, movementDataLength), dragon.getPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,14 +143,15 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
Point startPos = new Point(start_x, start_y - 2);
|
||||
Point serverStartPos = new Point(monster.getPosition());
|
||||
long movementDataStart = slea.getPosition();
|
||||
updatePosition(slea, monster, -2);
|
||||
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
|
||||
|
||||
Boolean aggro = monster.aggroMoveLifeUpdate(player);
|
||||
if (aggro == null) return;
|
||||
|
||||
if (nextUse != null) {
|
||||
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro, nextSkillId, nextSkillLevel));
|
||||
|
||||
updatePosition(slea, monster, -2); // Thanks Doodle and ZERO傑洛 for noticing sponge-based bosses moving out of stage in case of no-offset applied
|
||||
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
|
||||
|
||||
Boolean aggro = monster.aggroMoveLifeUpdate(player);
|
||||
if (aggro == null) return;
|
||||
|
||||
if (nextUse != null) {
|
||||
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro, nextSkillId, nextSkillLevel));
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro));
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ public final class MoveSummonHandler extends AbstractMovementPacketHandler {
|
||||
break;
|
||||
}
|
||||
}
|
||||
long movementDataStart = slea.getPosition();
|
||||
updatePosition(slea, summon, 0);
|
||||
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
|
||||
if (summon != null) {
|
||||
long movementDataStart = slea.getPosition();
|
||||
updatePosition(slea, summon, 0);
|
||||
long movementDataLength = slea.getPosition() - movementDataStart; //how many bytes were read by updatePosition
|
||||
slea.seek(movementDataStart);
|
||||
player.getMap().broadcastMessage(player, MaplePacketCreator.moveSummon(player.getId(), oid, startPos, slea, movementDataLength), summon.getPosition());
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ import tools.data.input.SeekableLittleEndianAccessor;
|
||||
* @author Ronan
|
||||
*/
|
||||
public final class PetExcludeItemsHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
final int petId = slea.readInt();
|
||||
slea.skip(4);
|
||||
|
||||
@@ -203,6 +203,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
if (!newcomer) {
|
||||
c.setLanguage(player.getClient().getLanguage());
|
||||
c.setCharacterSlots((byte) player.getClient().getCharacterSlots());
|
||||
player.newClient(c);
|
||||
}
|
||||
|
||||
@@ -26,9 +26,14 @@ import client.MapleClient;
|
||||
import client.Skill;
|
||||
import client.SkillFactory;
|
||||
import client.autoban.AutobanFactory;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MapleWeaponType;
|
||||
import client.status.MonsterStatusEffect;
|
||||
import constants.skills.Outlaw;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.MapleStatEffect;
|
||||
import server.life.MapleMonster;
|
||||
import server.life.MapleMonsterInformationProvider;
|
||||
@@ -115,15 +120,29 @@ public final class SummonDamageHandler extends AbstractDealDamageHandler {
|
||||
player.getMap().damageMonster(player, target, damage);
|
||||
}
|
||||
}
|
||||
|
||||
if (summon.getSkill() == Outlaw.GAVIOTA) { // thanks Periwinks for noticing Gaviota not cancelling after grenade toss
|
||||
player.cancelEffect(summonEffect, false, -1);
|
||||
}
|
||||
}
|
||||
|
||||
private static int calcMaxDamage(MapleStatEffect summonEffect, MapleCharacter player, boolean magic) {
|
||||
double maxDamage;
|
||||
|
||||
if (magic) {
|
||||
maxDamage = player.calculateMaxBaseMagicDamage() * (0.05 * summonEffect.getMatk());
|
||||
int matk = Math.max(player.getTotalMagic(), 14);
|
||||
maxDamage = player.calculateMaxBaseMagicDamage(matk) * (0.05 * summonEffect.getMatk());
|
||||
} else {
|
||||
int maxBaseDmg = player.calculateMaxBaseDamage(player.getTotalWatk()); // thanks Conrad for detecting some summons legitimately hitting over the calculated limit
|
||||
int watk = Math.max(player.getTotalWatk(), 14);
|
||||
Item weapon_item = player.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -11);
|
||||
|
||||
int maxBaseDmg; // thanks Conrad, Atoot for detecting some summons legitimately hitting over the calculated limit
|
||||
if (weapon_item != null) {
|
||||
maxBaseDmg = player.calculateMaxBaseDamage(watk, MapleItemInformationProvider.getInstance().getWeaponType(weapon_item.getItemId()));
|
||||
} else {
|
||||
maxBaseDmg = player.calculateMaxBaseDamage(watk, MapleWeaponType.SWORD1H);
|
||||
}
|
||||
|
||||
float summonDmgMod = (maxBaseDmg >= 438) ? 0.054f : 0.077f;
|
||||
maxDamage = maxBaseDmg * (summonDmgMod * summonEffect.getWatk());
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ public class MapleMatchCheckerCoordinator {
|
||||
}
|
||||
|
||||
private void disposeMatchElement(MapleMatchCheckingElement mmce) {
|
||||
Set<Integer> matchPlayers = mmce.getMatchPlayers();
|
||||
Set<Integer> matchPlayers = mmce.getMatchPlayers(); // thanks Ai for noticing players getting match-stuck on certain cases
|
||||
while (!poolMatchPlayers(matchPlayers)) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
|
||||
@@ -47,6 +47,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
@@ -130,7 +131,7 @@ public class World {
|
||||
|
||||
private Set<Integer> queuedGuilds = new HashSet<>();
|
||||
private Map<Integer, Pair<Pair<Boolean, Boolean>, Pair<Integer, Integer>>> queuedMarriages = new HashMap<>();
|
||||
private Map<Integer, Set<Integer>> marriageGuests = new HashMap<>();
|
||||
private Map<Integer, Set<Integer>> marriageGuests = new ConcurrentHashMap<>();
|
||||
|
||||
private Map<Integer, Integer> partyChars = new HashMap<>();
|
||||
private Map<Integer, MapleParty> parties = new HashMap<>();
|
||||
@@ -720,7 +721,7 @@ public class World {
|
||||
return new Pair<>(type, guests);
|
||||
}
|
||||
|
||||
public synchronized boolean addMarriageGuest(int marriageId, int playerId) {
|
||||
public boolean addMarriageGuest(int marriageId, int playerId) {
|
||||
Set<Integer> guests = marriageGuests.get(marriageId);
|
||||
if(guests != null) {
|
||||
if(guests.contains(playerId)) return false;
|
||||
|
||||
Reference in New Issue
Block a user