Item pickup patch + Rescaled buyback fee + Tameness gain on Quests

Fixed a concurrency issue with registering picked items into the inventory, that would render some of the collected items to not be registered.
Adjusted buyback fee, now using a value sensitive to the player level (starts scaling from level 30, caps at 120).
Edited MaxHP of the boss Shade, now properly scaled to it's level.
Fixed return scroll and summon bags being usable inside BRPQ rest points.
Added missing etc drop data for the Extras/Leaders mobs from Zipangu.
Implemented pet tameness gain on quests.
Fixed a concurrency issue with the pet spawn handler, allowing possible PE exploits.
Adjusted drop rates of omok pieces and match cards, now somewhat GMS-like.
Shadow Meso now properly dispels mobs wdef/mdef up, as the skill description suggests.
Fixed Shadow Meso using up projectiles (it should use only mesos).
This commit is contained in:
ronancpl
2018-06-26 22:56:26 -03:00
parent c10856546f
commit dac5c43635
69 changed files with 925 additions and 550 deletions
+17 -6
View File
@@ -5230,6 +5230,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return lastBuyback + ServerConstants.BUYBACK_COOLDOWN_MINUTES * 60 * 1000;
}
private int getBuybackFee() {
float fee = ServerConstants.BUYBACK_FEE;
int grade = Math.min(Math.max(level, 30), 120) - 30;
fee += (grade * ServerConstants.BUYBACK_LEVEL_STACK_FEE);
return (int) Math.floor(fee);
}
public boolean couldBuyback() { // Ronan's buyback system
long timeNow = System.currentTimeMillis();
@@ -5249,7 +5257,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
boolean usingMesos = ServerConstants.USE_BUYBACK_WITH_MESOS;
int fee = ServerConstants.BUYBACK_FEE;
int fee = getBuybackFee();
if(usingMesos) fee *= ServerConstants.BUYBACK_MESO_MULTIPLIER;
if(!canBuyback(fee, usingMesos)) {
@@ -5867,7 +5875,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
for (Pair<Item, MapleInventoryType> item : ItemFactory.INVENTORY.loadItems(ret.id, !channelserver)) {
sandboxCheck |= item.getLeft().getFlag();
ret.getInventory(item.getRight()).addFromDB(item.getLeft());
ret.getInventory(item.getRight()).addItemFromDB(item.getLeft());
Item itemz = item.getLeft();
if (itemz.getPetId() > -1) {
MaplePet pet = itemz.getPet();
@@ -7977,12 +7985,15 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void unequipPet(MaplePet pet, boolean shift_left, boolean hunger) {
if (this.getPet(this.getPetIndex(pet)) != null) {
this.getPet(this.getPetIndex(pet)).setSummoned(false);
this.getPet(this.getPetIndex(pet)).saveToDb();
byte petIdx = this.getPetIndex(pet);
MaplePet chrPet = this.getPet(petIdx);
if (chrPet != null) {
chrPet.setSummoned(false);
chrPet.saveToDb();
}
this.getClient().getWorldServer().unregisterPetHunger(this, getPetIndex(pet));
this.getClient().getWorldServer().unregisterPetHunger(this, petIdx);
getMap().broadcastMessage(this, MaplePacketCreator.showPet(this, pet, true, hunger), true);
removePet(pet, shift_left);
+1 -1
View File
@@ -948,7 +948,7 @@ public class MapleClient {
}
}
private void clear() { //usable when defining client = null shortly after
private void clear() {
// player hard reference removal thanks to Steve (kaito1410)
if (this.player != null) {
this.player.empty(true); // clears schedules and stuff
+4 -4
View File
@@ -60,25 +60,25 @@ public abstract class CharacterFactory {
if(top > 0) {
Item eq_top = ii.getEquipById(top);
eq_top.setPosition((byte) -5);
equipped.addFromDB(eq_top);
equipped.addItemFromDB(eq_top);
}
if(bottom > 0) {
Item eq_bottom = ii.getEquipById(bottom);
eq_bottom.setPosition((byte) -6);
equipped.addFromDB(eq_bottom);
equipped.addItemFromDB(eq_bottom);
}
if(shoes > 0) {
Item eq_shoes = ii.getEquipById(shoes);
eq_shoes.setPosition((byte) -7);
equipped.addFromDB(eq_shoes);
equipped.addItemFromDB(eq_shoes);
}
if(weapon > 0) {
Item eq_weapon = ii.getEquipById(weapon);
eq_weapon.setPosition((byte) -11);
equipped.addFromDB(eq_weapon.copy());
equipped.addItemFromDB(eq_weapon.copy());
}
if (!newchar.insertNewChar(recipe)) {
+32 -10
View File
@@ -214,20 +214,19 @@ public class MapleInventory implements Iterable<Item> {
}
public short addItem(Item item) {
short slotId = getNextFreeSlot();
if (slotId < 0 || item == null) {
short slotId = addSlot(item);
if (slotId == -1) {
return -1;
}
addSlot(slotId, item);
item.setPosition(slotId);
return slotId;
}
public void addFromDB(Item item) {
public void addItemFromDB(Item item) {
if (item.getPosition() < 0 && !type.equals(MapleInventoryType.EQUIPPED)) {
return;
}
addSlot(item.getPosition(), item);
addSlotFromDB(item.getPosition(), item);
}
private static boolean isSameOwner(Item source, Item target) {
@@ -302,16 +301,39 @@ public class MapleInventory implements Iterable<Item> {
}
}
public void addSlot(short slot, Item item) {
private short addSlot(Item item) {
if(item == null) {
return -1;
}
lock.lock();
try {
inventory.put(slot, item);
short slotId = getNextFreeSlot();
if (slotId < 0) {
return -1;
}
inventory.put(slotId, item);
if(ItemConstants.isRateCoupon(item.getItemId())) {
owner.updateCouponRates();
}
return slotId;
} finally {
lock.unlock();
}
if(ItemConstants.isRateCoupon(item.getItemId())) {
owner.updateCouponRates();
}
private void addSlotFromDB(short slot, Item item) {
lock.lock();
try {
inventory.put(slot, item);
if(ItemConstants.isRateCoupon(item.getItemId())) {
owner.updateCouponRates();
}
} finally {
lock.unlock();
}
}
@@ -498,10 +498,10 @@ public class MapleInventoryManipulator {
}
source.setPosition(dst);
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addFromDB(source);
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addItemFromDB(source);
if (target != null) {
target.setPosition(src);
c.getPlayer().getInventory(MapleInventoryType.EQUIP).addFromDB(target);
c.getPlayer().getInventory(MapleInventoryType.EQUIP).addItemFromDB(target);
}
if (c.getPlayer().getBuffedValue(MapleBuffStat.BOOSTER) != null && ItemConstants.isWeapon(source.getItemId())) {
c.getPlayer().cancelBuffStats(MapleBuffStat.BOOSTER);
@@ -536,10 +536,10 @@ public class MapleInventoryManipulator {
c.getPlayer().getInventory(MapleInventoryType.EQUIP).removeSlot(dst);
}
source.setPosition(dst);
c.getPlayer().getInventory(MapleInventoryType.EQUIP).addFromDB(source);
c.getPlayer().getInventory(MapleInventoryType.EQUIP).addItemFromDB(source);
if (target != null) {
target.setPosition(src);
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addFromDB(target);
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addItemFromDB(target);
}
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(2, source, src))));
c.getPlayer().equipChanged();
@@ -0,0 +1,99 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2018 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 client.processor;
import client.MapleCharacter;
import java.awt.Point;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import client.SkillFactory;
import provider.MapleDataTool;
import client.inventory.manipulator.MapleInventoryManipulator;
import java.io.File;
import provider.MapleDataProvider;
import provider.MapleDataProviderFactory;
import tools.MaplePacketCreator;
/**
*
* @author RonanLana (just added locking on OdinMS' SpawnPetHandler method body)
*/
public class SpawnPetProcessor {
private static MapleDataProvider dataRoot = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Item.wz"));
public static void processSpawnPet(MapleClient c, byte slot, boolean lead) {
c.lockClient();
try {
MapleCharacter chr = c.getPlayer();
MaplePet pet = chr.getInventory(MapleInventoryType.CASH).getItem(slot).getPet();
if (pet == null) return;
int petid = pet.getItemId();
if (petid == 5000028 || petid == 5000047) //Handles Dragon AND Robos
{
if (chr.haveItem(petid + 1)) {
chr.dropMessage(5, "You can't hatch your " + (petid == 5000028 ? "Dragon egg" : "Robo egg") + " if you already have a Baby " + (petid == 5000028 ? "Dragon." : "Robo."));
c.announce(MaplePacketCreator.enableActions());
return;
} else {
int evolveid = MapleDataTool.getInt("info/evol1", dataRoot.getData("Pet/" + petid + ".img"));
int petId = MaplePet.createPet(evolveid);
if (petId == -1) {
return;
}
long expiration = chr.getInventory(MapleInventoryType.CASH).getItem(slot).getExpiration();
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, petid, (short) 1, false, false);
MapleInventoryManipulator.addById(c, evolveid, (short) 1, null, petId, expiration);
pet.deleteFromDb();
c.announce(MaplePacketCreator.enableActions());
return;
}
}
if (chr.getPetIndex(pet) != -1) {
chr.unequipPet(pet, true);
} else {
if (chr.getSkillLevel(SkillFactory.getSkill(8)) == 0 && chr.getPet(0) != null) {
chr.unequipPet(chr.getPet(0), false);
}
if (lead) {
chr.shiftPetsRight();
}
Point pos = chr.getPosition();
pos.y -= 12;
pet.setPos(pos);
pet.setFh(chr.getMap().getFootholds().findBelow(pet.getPos()).getId());
pet.setStance(0);
pet.setSummoned(true);
pet.saveToDb();
chr.addPet(pet);
chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showPet(c.getPlayer(), pet, false, false), true);
c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer()));
c.announce(MaplePacketCreator.enableActions());
chr.commitExcludedItems();
chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(pet));
}
} finally {
c.unlockClient();
}
}
}
+3 -2
View File
@@ -105,7 +105,7 @@ public class ServerConstants {
public static String TIMEZONE = "-GMT3";
public static boolean USE_DISPLAY_NUMBERS_WITH_COMMA = true; //Enforce comma on displayed strings (use this when USE_UNITPRICE_WITH_COMMA is active and you still want to display comma-separated values).
public static boolean USE_UNITPRICE_WITH_COMMA = true; //Set this accordingly with the layout of the unitPrices on Item.wz XML's, whether it's using commas or dots to represent fractions.
public static final byte MIN_UNDERLEVEL_TO_EXP_GAIN = 5; //Characters are unable to get EXP from a mob if their level are under this threshold, only if "USE_ENFORCE_MOB_LEVEL_RANGE" is enabled. For bosses, this attribute is doubled.
public static final byte MIN_UNDERLEVEL_TO_EXP_GAIN = 20; //Characters are unable to get EXP from a mob if their level are under this threshold, only if "USE_ENFORCE_MOB_LEVEL_RANGE" is enabled. For bosses, this attribute is doubled.
public static final byte MAX_MONITORED_BUFFSTATS = 5; //Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires.
public static final int MAX_AP = 32767; //Max AP allotted on the auto-assigner.
public static final int MAX_EVENT_LEVELS = 8; //Event has different levels of rewarding system.
@@ -206,7 +206,8 @@ public class ServerConstants {
//Buyback Configuration
public static final boolean USE_BUYBACK_WITH_MESOS = true; //Enables usage of either mesos or NX for the buyback fee.
public static final int BUYBACK_FEE = 7770; //Sets the amount needed to buyback.
public static final float BUYBACK_FEE = 77.70f; //Sets the base amount needed to buyback (level 30 or under will use the base value).
public static final float BUYBACK_LEVEL_STACK_FEE = 85.47f; //Sets the level-stacking portion of the amount needed to buyback (fee will sum up linearly until level 120, when it reaches the peak).
public static final int BUYBACK_MESO_MULTIPLIER = 1000; //Sets a multiplier for the fee when using meso as the charge unit.
public static final int BUYBACK_RETURN_MINUTES = 1; //Sets the maximum amount of time the player can wait before decide to buyback.
public static final int BUYBACK_COOLDOWN_MINUTES = 7; //Sets the time the player must wait before using buyback again.
@@ -573,6 +573,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
} else {
ret.charge = 0;
}
lea.skip(8);
ret.display = lea.readByte();
ret.direction = lea.readByte();
@@ -674,10 +675,10 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
calcDmgMax = (int) Math.round((chr.getTotalInt() * 4.8 + chr.getTotalLuk() * 4) * chr.getTotalMagic() / 1000);
calcDmgMax = calcDmgMax * effect.getHp() / 100;
}
} else if(ret.skill == Hermit.SHADOW_MESO) {
// Shadow Meso also has its own formula
calcDmgMax = effect.getMoneyCon() * 10;
calcDmgMax = (int) Math.floor(calcDmgMax * 1.5);
} else if(ret.skill == Hermit.SHADOW_MESO) {
// Shadow Meso also has its own formula
calcDmgMax = effect.getMoneyCon() * 10;
calcDmgMax = (int) Math.floor(calcDmgMax * 1.5);
} else {
// Normal damage formula for skills
calcDmgMax = calcDmgMax * effect.getDamage() / 100;
@@ -812,6 +813,10 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
if(monster != null) {
calcDmgMax = monster.getHp() / (50 - chr.getSkillLevel(skill));
}
} else if(ret.skill == Hermit.SHADOW_MESO) {
if(monster != null) {
monster.debuffMob(Hermit.SHADOW_MESO);
}
}
}
@@ -22,6 +22,7 @@
package net.server.channel.handlers;
import client.MapleClient;
import client.MapleCharacter;
import net.AbstractMaplePacketHandler;
import server.maps.MapleMap;
import tools.MaplePacketCreator;
@@ -39,9 +40,11 @@ public final class MobDamageMobHandler extends AbstractMaplePacketHandler {
int to = slea.readInt();
slea.readByte();
int dmg = slea.readInt();
MapleMap map = c.getPlayer().getMap();
MapleCharacter chr = c.getPlayer();
MapleMap map = chr.getMap();
if (map.getMonsterByOid(from) != null && map.getMonsterByOid(to) != null) {
map.damageMonster(c.getPlayer(), map.getMonsterByOid(to), dmg);
map.damageMonster(chr, map.getMonsterByOid(to), dmg);
map.broadcastMessage(MaplePacketCreator.damageMonster(to, dmg));
}
}
@@ -30,7 +30,6 @@ import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleClient;
import client.MapleJob;
import client.Skill;
import client.SkillFactory;
import client.inventory.Item;
@@ -113,6 +112,20 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
if (effect.getCooldown() > 0) {
c.announce(MaplePacketCreator.skillCooldown(attack.skill, effect.getCooldown()));
}
if(attack.skill == 4111004) { // shadow meso
bulletCount = 0;
int money = effect.getMoneyCon();
if (money != 0) {
int moneyMod = money / 2;
money += Randomizer.nextInt(moneyMod);
if (money > chr.getMeso()) {
money = chr.getMeso();
}
chr.gainMeso(-money, false);
}
}
}
boolean hasShadowPartner = chr.getBuffedValue(MapleBuffStat.SHADOWPARTNER) != null;
if (hasShadowPartner) {
@@ -165,7 +178,8 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
else MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, slot, bulletConsume, false, true);
}
}
if (projectile != 0 || soulArrow || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006) {
if (projectile != 0 || soulArrow || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006 || attack.skill == 4111004) {
int visProjectile = projectile; //visible projectile sent to players
if (ItemConstants.isThrowingStar(projectile)) {
MapleInventory cash = chr.getInventory(MapleInventoryType.CASH);
@@ -178,10 +192,10 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
}
}
}
} else //bow, crossbow
if (soulArrow || attack.skill == 3111004 || attack.skill == 3211004 || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006) {
} else if (soulArrow || attack.skill == 3111004 || attack.skill == 3211004 || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006) {
visProjectile = 0;
}
byte[] packet;
switch (attack.skill) {
case 3121004: // Hurricane
@@ -195,17 +209,7 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
break;
}
chr.getMap().broadcastMessage(chr, packet, false, true);
if (effect != null) {
int money = effect.getMoneyCon();
if (money != 0) {
int moneyMod = money / 2;
money += Randomizer.nextInt(moneyMod);
if (money > chr.getMeso()) {
money = chr.getMeso();
}
chr.gainMeso(-money, false);
}
}
if (attack.skill != 0) {
Skill skill = SkillFactory.getSkill(attack.skill);
MapleStatEffect effect_ = skill.getEffect(chr.getSkillLevel(skill));
@@ -21,78 +21,20 @@
*/
package net.server.channel.handlers;
import client.MapleCharacter;
import java.awt.Point;
import java.io.File;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import client.SkillFactory;
import client.processor.SpawnPetProcessor;
import net.AbstractMaplePacketHandler;
import provider.MapleDataProvider;
import provider.MapleDataProviderFactory;
import provider.MapleDataTool;
import client.inventory.manipulator.MapleInventoryManipulator;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class SpawnPetHandler extends AbstractMaplePacketHandler {
private static MapleDataProvider dataRoot = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Item.wz"));
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
slea.readInt();
byte slot = slea.readByte();
slea.readByte();
boolean lead = slea.readByte() == 1;
MaplePet pet = chr.getInventory(MapleInventoryType.CASH).getItem(slot).getPet();
if (pet == null) return;
int petid = pet.getItemId();
if (petid == 5000028 || petid == 5000047) //Handles Dragon AND Robos
{
if (chr.haveItem(petid + 1)) {
chr.dropMessage(5, "You can't hatch your " + (petid == 5000028 ? "Dragon egg" : "Robo egg") + " if you already have a Baby " + (petid == 5000028 ? "Dragon." : "Robo."));
c.announce(MaplePacketCreator.enableActions());
return;
} else {
int evolveid = MapleDataTool.getInt("info/evol1", dataRoot.getData("Pet/" + petid + ".img"));
int petId = MaplePet.createPet(evolveid);
if (petId == -1) {
return;
}
long expiration = chr.getInventory(MapleInventoryType.CASH).getItem(slot).getExpiration();
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, petid, (short) 1, false, false);
MapleInventoryManipulator.addById(c, evolveid, (short) 1, null, petId, expiration);
pet.deleteFromDb();
c.announce(MaplePacketCreator.enableActions());
return;
}
}
if (chr.getPetIndex(pet) != -1) {
chr.unequipPet(pet, true);
} else {
if (chr.getSkillLevel(SkillFactory.getSkill(8)) == 0 && chr.getPet(0) != null) {
chr.unequipPet(chr.getPet(0), false);
}
if (lead) {
chr.shiftPetsRight();
}
Point pos = chr.getPosition();
pos.y -= 12;
pet.setPos(pos);
pet.setFh(chr.getMap().getFootholds().findBelow(pet.getPos()).getId());
pet.setStance(0);
pet.setSummoned(true);
pet.saveToDb();
chr.addPet(pet);
chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showPet(c.getPlayer(), pet, false, false), true);
c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer()));
c.announce(MaplePacketCreator.enableActions());
chr.commitExcludedItems();
chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(pet));
}
SpawnPetProcessor.processSpawnPet(c, slot, lead);
}
}
+1 -1
View File
@@ -786,7 +786,7 @@ public class AbstractPlayerInteraction {
}
final Item newItem = MapleItemInformationProvider.getInstance().getEquipById(itemid);
newItem.setPosition(slot);
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addFromDB(newItem);
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).addItemFromDB(newItem);
c.announce(MaplePacketCreator.modifyInventory(false, Collections.singletonList(new ModifyInventory(0, newItem))));
}
+5 -1
View File
@@ -52,7 +52,11 @@ public abstract class AbstractScriptManager {
path = "scripts/" + path;
engine = null;
if (c != null) {
engine = c.getScriptEngine(path);
try {
engine = c.getScriptEngine(path);
} catch (NullPointerException npe) {
c = null; // player disconnected
}
}
if (engine == null) {
File scriptFile = new File(path);
@@ -265,9 +265,12 @@ public class ReactorActionManager extends AbstractPlayerInteraction {
MapleMonster mm = map.getMonsterById(id);
if(mm != null) {
int damage = (int)Math.ceil(mm.getMaxHp() / hitsToKill);
MapleCharacter chr = this.getPlayer();
map.damageMonster(this.getPlayer(), mm, damage);
map.broadcastMessage(MaplePacketCreator.damageMonster(mm.getObjectId(), damage));
if(chr != null) {
map.damageMonster(chr, mm, damage);
map.broadcastMessage(MaplePacketCreator.damageMonster(mm.getObjectId(), damage));
}
}
}
+26 -16
View File
@@ -31,11 +31,12 @@ import client.status.MonsterStatus;
import client.status.MonsterStatusEffect;
import constants.ServerConstants;
import constants.skills.Crusader;
import constants.skills.DragonKnight;
import constants.skills.FPMage;
import constants.skills.Hermit;
import constants.skills.ILMage;
import constants.skills.NightLord;
import constants.skills.NightWalker;
import constants.skills.Priest;
import constants.skills.Shadower;
import constants.skills.WhiteKnight;
import java.awt.Point;
@@ -999,29 +1000,38 @@ public class MapleMonster extends AbstractLoadedMapleLife {
byte[] packet = MaplePacketCreator.cancelMonsterStatus(getObjectId(), oldEffect.getStati());
map.broadcastMessage(packet, getPosition());
MapleCharacter controller = getController();
if (controller != null && !controller.isMapObjectVisible(MapleMonster.this)) {
controller.getClient().announce(packet);
MapleCharacter chrController = getController();
if (chrController != null && !chrController.isMapObjectVisible(MapleMonster.this)) {
chrController.getClient().announce(packet);
}
stati.remove(stat);
}
}
public void debuffMob(int skillid) {
MonsterStatus[] stats = {MonsterStatus.WEAPON_ATTACK_UP, MonsterStatus.WEAPON_DEFENSE_UP, MonsterStatus.MAGIC_ATTACK_UP};
MonsterStatus[] statups = {MonsterStatus.WEAPON_ATTACK_UP, MonsterStatus.WEAPON_DEFENSE_UP, MonsterStatus.MAGIC_ATTACK_UP, MonsterStatus.MAGIC_DEFENSE_UP};
statiLock.lock();
try {
int i = (skillid == Crusader.ARMOR_CRASH ? 1 : (skillid == WhiteKnight.MAGIC_CRASH ? 2 : 0));
debuffMobStat(stats[i]);
if(ServerConstants.USE_ANTI_IMMUNITY_CRASH) {
if (skillid == Crusader.ARMOR_CRASH) {
if(!isBuffed(MonsterStatus.WEAPON_REFLECT)) debuffMobStat(MonsterStatus.WEAPON_IMMUNITY);
if(!isBuffed(MonsterStatus.MAGIC_REFLECT)) debuffMobStat(MonsterStatus.MAGIC_IMMUNITY);
} else if (skillid == WhiteKnight.MAGIC_CRASH) {
if(!isBuffed(MonsterStatus.MAGIC_REFLECT)) debuffMobStat(MonsterStatus.MAGIC_IMMUNITY);
} else {
if(!isBuffed(MonsterStatus.WEAPON_REFLECT)) debuffMobStat(MonsterStatus.WEAPON_IMMUNITY);
if(skillid == Hermit.SHADOW_MESO) {
debuffMobStat(statups[1]);
debuffMobStat(statups[3]);
} else if(skillid == Priest.DISPEL) {
for(MonsterStatus ms : statups) {
debuffMobStat(ms);
}
} else { // is a crash skill
int i = (skillid == Crusader.ARMOR_CRASH ? 1 : (skillid == WhiteKnight.MAGIC_CRASH ? 2 : 0));
debuffMobStat(statups[i]);
if(ServerConstants.USE_ANTI_IMMUNITY_CRASH) {
if (skillid == Crusader.ARMOR_CRASH) {
if(!isBuffed(MonsterStatus.WEAPON_REFLECT)) debuffMobStat(MonsterStatus.WEAPON_IMMUNITY);
if(!isBuffed(MonsterStatus.MAGIC_REFLECT)) debuffMobStat(MonsterStatus.MAGIC_IMMUNITY);
} else if (skillid == WhiteKnight.MAGIC_CRASH) {
if(!isBuffed(MonsterStatus.MAGIC_REFLECT)) debuffMobStat(MonsterStatus.MAGIC_IMMUNITY);
} else {
if(!isBuffed(MonsterStatus.WEAPON_REFLECT)) debuffMobStat(MonsterStatus.WEAPON_IMMUNITY);
}
}
}
} finally {
+3
View File
@@ -518,6 +518,9 @@ public class MapleQuest {
case SKILL:
ret = new SkillAction(this, data);
break;
case PETTAMENESS:
ret = new PetTamenessAction(this, data);
break;
default:
//FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Unhandled Action Type: " + type.toString() + " QuestID: " + this.getId());
break;
+3 -1
View File
@@ -26,7 +26,7 @@ package server.quest;
* @author Matze
*/
public enum MapleQuestActionType {
UNDEFINED(-1), EXP(0), ITEM(1), NEXTQUEST(2), MESO(3), QUEST(4), SKILL(5), FAME(6), BUFF(7), PETSKILL(8), YES(9), NO(10), NPC(11), MIN_LEVEL(12), NORMAL_AUTO_START(13), ZERO(14);
UNDEFINED(-1), EXP(0), ITEM(1), NEXTQUEST(2), MESO(3), QUEST(4), SKILL(5), FAME(6), BUFF(7), PETSKILL(8), YES(9), NO(10), NPC(11), MIN_LEVEL(12), NORMAL_AUTO_START(13), PETTAMENESS(14), ZERO(15);
final byte type;
private MapleQuestActionType(int type) {
@@ -60,6 +60,8 @@ public enum MapleQuestActionType {
return MIN_LEVEL;
} else if (name.equals("normalAutoStart")) {
return NORMAL_AUTO_START;
} else if (name.equals("pettameness")) {
return PETTAMENESS;
} else if (name.equals("0")) {
return ZERO;
} else {
@@ -0,0 +1,63 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2018 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 server.quest.actions;
import client.MapleClient;
import client.MapleCharacter;
import client.inventory.MaplePet;
import provider.MapleData;
import provider.MapleDataTool;
import server.quest.MapleQuest;
import server.quest.MapleQuestActionType;
/**
*
* @author Ronan
*/
public class PetTamenessAction extends MapleQuestAction {
int tameness;
public PetTamenessAction(MapleQuest quest, MapleData data) {
super(MapleQuestActionType.PETTAMENESS, quest);
questID = quest.getId();
processData(data);
}
@Override
public void processData(MapleData data) {
tameness = MapleDataTool.getInt(data);
}
@Override
public void run(MapleCharacter chr, Integer extSelection) {
MapleClient c = chr.getClient();
MaplePet pet = chr.getPet(0); // assuming here only the pet leader will gain tameness
if(pet == null) return;
c.lockClient();
try {
pet.gainClosenessFullness(chr, tameness, 0, 0);
} finally {
c.unlockClient();
}
}
}