Vegas's spell + pet/mounts schedule revamp + CafePQ

Added Vega's Spell feature. Refactored mounts and pets schedules (now
one thread runs globally updating stats). Fixed Pet Ignore now saving to
DB. Fixed Flash Jump animation not appearing for other players just
after changing jobs. Fixed 3rd job, now as a proper event with timeout.
Introducing Brand-new PQ: CafePQ.
This commit is contained in:
ronancpl
2017-09-08 14:36:58 -03:00
parent 74b4ca4132
commit e064d5cbfa
210 changed files with 35387 additions and 46797 deletions

View File

@@ -201,7 +201,7 @@ public enum SendOpcode {
MOVE_PET(0xAA),
PET_CHAT(0xAB),
PET_NAMECHANGE(0xAC),
PET_SHOW(0xAD),
PET_EXCEPTION_LIST(0xAD),
PET_COMMAND(0xAE),
SPAWN_SPECIAL_MAPOBJECT(0xAF),
REMOVE_SPECIAL_MAPOBJECT(0xB0),
@@ -334,7 +334,8 @@ public enum SendOpcode {
ENABLE_TV(0x157),
MTS_OPERATION2(0x15B),
MTS_OPERATION(0x15C),
VICIOUS_HAMMER(0x162);
VICIOUS_HAMMER(0x162),
VEGA_SCROLL(0x166);
private int code = -2;
private SendOpcode(int code) {

View File

@@ -0,0 +1,41 @@
/*
This file is part of the OdinMS Maple Story Server
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/>.
*/
package net.server;
import net.server.world.World;
/**
* @author Ronan
*/
public class MountTirednessWorker implements Runnable {
private World wserv;
@Override
public void run() {
wserv.runMountSchedule();
}
public MountTirednessWorker(World world) {
wserv = world;
}
}

View File

@@ -0,0 +1,41 @@
/*
This file is part of the OdinMS Maple Story Server
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/>.
*/
package net.server;
import net.server.world.World;
/**
* @author Ronan
*/
public class PetFullnessWorker implements Runnable {
private World wserv;
@Override
public void run() {
wserv.runPetSchedule();
}
public PetFullnessWorker(World world) {
wserv = world;
}
}

View File

@@ -52,12 +52,16 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
int[] statGain = new int[4];
int[] statEqpd = new int[4];
statGain[0] = 0; statGain[1] = 0; statGain[2] = 0; statGain[3] = 0;
slea.skip(8);
if (chr.getRemainingAp() < 1) return;
if(ServerConstants.USE_ANOTHER_AUTOASSIGNER == true) {
// ---------- Ronan Lana's AUTOASSIGNER -------------
if(ServerConstants.USE_SERVER_AUTOASSIGNER) {
// --------- Ronan Lana's AUTOASSIGNER ---------
// This method excels for assigning APs in such a way to cover all equipments AP requirements.
int str = 0, dex = 0, luk = 0, int_ = 0;
@@ -84,6 +88,11 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
int_ += nEquip.getInt();
}
statEqpd[0] = str;
statEqpd[1] = dex;
statEqpd[2] = luk;
statEqpd[3] = int_;
Collections.sort(eqpStrList, Collections.reverseOrder());
Collections.sort(eqpDexList, Collections.reverseOrder());
Collections.sort(eqpLukList, Collections.reverseOrder());
@@ -100,7 +109,7 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
MapleJob stance = c.getPlayer().getJobStyle();
int prStat = 0, scStat = 0, trStat = 0, temp, tempAp = chr.getRemainingAp(), CAP;
MapleStat primary, secondary, tertiary = MapleStat.INT;
MapleStat primary, secondary, tertiary = MapleStat.LUK;
switch(stance) {
case MAGICIAN:
CAP = 165;
@@ -124,6 +133,7 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
primary = MapleStat.INT;
secondary = MapleStat.LUK;
tertiary = MapleStat.DEX;
break;
@@ -197,6 +207,7 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
scStat += temp;
tempAp -= temp;
// thieves will upgrade STR as well only if a level-based threshold is reached.
if(chr.getStr() >= Math.max(13, (int)(0.4 * chr.getLevel()))) {
if(chr.getStr() < 50) {
trStat = (chr.getLevel() - 10) - (chr.getStr() + str - eqpStr);
@@ -205,7 +216,6 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
trStat = Math.min(50 - chr.getStr(), trStat);
trStat = Math.min(tempAp, trStat);
tempAp -= trStat;
tertiary = MapleStat.STR;
}
temp = (20 + (chr.getLevel() / 2)) - Math.max(50, trStat + chr.getStr() + str - eqpStr);
@@ -234,6 +244,7 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
primary = MapleStat.LUK;
secondary = MapleStat.DEX;
tertiary = MapleStat.STR;
break;
@@ -289,25 +300,28 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
}
//-------------------------------------------------------------------------------------
int total = 0;
int extras = 0;
total += trStat;
extras += gainStatByType(chr, tertiary, trStat);
extras = gainStatByType(chr, primary, statGain, statEqpd, prStat + extras);
extras = gainStatByType(chr, secondary, statGain, statEqpd, scStat + extras);
extras = gainStatByType(chr, tertiary, statGain, statEqpd, trStat + extras);
if(extras > 0) { //redistribute surplus in priority order
extras = gainStatByType(chr, primary, statGain, statEqpd, extras);
extras = gainStatByType(chr, secondary, statGain, statEqpd, extras);
extras = gainStatByType(chr, tertiary, statGain, statEqpd, extras);
gainStatByType(chr, getQuaternaryStat(stance), statGain, statEqpd, extras);
}
total += scStat;
extras += gainStatByType(chr, secondary, scStat);
total += prStat;
extras += gainStatByType(chr, primary, prStat);
int remainingAp = (chr.getRemainingAp() - total) + extras;
int remainingAp = (chr.getRemainingAp() - getAccumulatedStatGain(statGain));
chr.setRemainingAp(remainingAp);
chr.updateSingleStat(MapleStat.AVAILABLEAP, remainingAp);
c.announce(MaplePacketCreator.enableActions());
//----------------------------------------------------------------------------------------
c.announce(MaplePacketCreator.serverNotice(1, "Better AP applications detected:\r\nSTR: +" + str + "\r\nDEX: +" + dex + "\r\nINT: +" + int_ + "\r\nLUK: +" + luk));
c.announce(MaplePacketCreator.serverNotice(1, "Better AP applications detected:\r\nSTR: +" + statGain[0] + "\r\nDEX: +" + statGain[1] + "\r\nINT: +" + statGain[3] + "\r\nLUK: +" + statGain[2]));
}
else {
int total = 0;
@@ -317,6 +331,18 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
c.disconnect(false, false);
return;
}
MapleInventory iv = chr.getInventory(MapleInventoryType.EQUIPPED);
Collection<Item> equippedC = iv.list();
for (Item item : equippedC) { //selecting the biggest AP value of each stat from each equipped item.
Equip nEquip = (Equip)item;
statEqpd[0] += nEquip.getStr();
statEqpd[1] += nEquip.getDex();
statEqpd[2] += nEquip.getLuk();
statEqpd[3] += nEquip.getInt();
}
for (int i = 0; i < 2; i++) {
int type = slea.readInt();
int tempVal = slea.readInt();
@@ -324,8 +350,7 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
return;
}
total += tempVal;
System.out.println(tempVal);
extras += gainStatByType(chr, MapleStat.getBy5ByteEncoding(type), tempVal);
extras += gainStatByType(chr, MapleStat.getBy5ByteEncoding(type), statGain, statEqpd, tempVal);
}
int remainingAp = (chr.getRemainingAp() - total) + extras;
chr.setRemainingAp(remainingAp);
@@ -334,37 +359,48 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
}
}
private int gainStatByType(MapleCharacter chr, MapleStat type, int gain) {
private int gainStatByType(MapleCharacter chr, MapleStat type, int[] statGain, int[] statEqpd, int gain) {
if(gain <= 0) return 0;
int newVal = 0;
if (type.equals(MapleStat.STR)) {
newVal = chr.getStr() + gain;
newVal = chr.getStr() + statEqpd[0] + gain;
if (newVal > ServerConstants.MAX_AP) {
chr.setStr(ServerConstants.MAX_AP);
statGain[0] += gain - (newVal - ServerConstants.MAX_AP);
chr.setStr(ServerConstants.MAX_AP - statEqpd[0]);
} else {
statGain[0] += gain;
chr.setStr(newVal);
}
} else if (type.equals(MapleStat.INT)) {
newVal = chr.getInt() + gain;
newVal = chr.getInt() + statEqpd[3] + gain;
if (newVal > ServerConstants.MAX_AP) {
chr.setInt(ServerConstants.MAX_AP);
statGain[3] += gain - (newVal - ServerConstants.MAX_AP);
chr.setInt(ServerConstants.MAX_AP - statEqpd[3]);
} else {
statGain[3] += gain;
chr.setInt(newVal);
}
} else if (type.equals(MapleStat.LUK)) {
newVal = chr.getLuk() + gain;
newVal = chr.getLuk() + statEqpd[2] + gain;
if (newVal > ServerConstants.MAX_AP) {
chr.setLuk(ServerConstants.MAX_AP);
statGain[2] += gain - (newVal - ServerConstants.MAX_AP);
chr.setLuk(ServerConstants.MAX_AP - statEqpd[2]);
} else {
statGain[2] += gain;
chr.setLuk(newVal);
}
} else if (type.equals(MapleStat.DEX)) {
newVal = chr.getDex() + gain;
newVal = chr.getDex() + statEqpd[1] + gain;
if (newVal > ServerConstants.MAX_AP) {
chr.setDex(ServerConstants.MAX_AP);
statGain[1] += gain - (newVal - ServerConstants.MAX_AP);
chr.setDex(ServerConstants.MAX_AP - statEqpd[1]);
} else {
statGain[1] += gain;
chr.setDex(newVal);
}
}
if (newVal > ServerConstants.MAX_AP) {
chr.updateSingleStat(type, ServerConstants.MAX_AP);
return newVal - ServerConstants.MAX_AP;
@@ -372,4 +408,19 @@ public class AutoAssignHandler extends AbstractMaplePacketHandler {
chr.updateSingleStat(type, newVal);
return 0;
}
private MapleStat getQuaternaryStat(MapleJob stance) {
if(stance != MapleJob.MAGICIAN) return MapleStat.INT;
return MapleStat.STR;
}
private int getAccumulatedStatGain(int[] statGain) {
int acc = 0;
for(byte i = 0; i < statGain.length; i++) {
acc += statGain[i];
}
return acc;
}
}

View File

@@ -88,6 +88,7 @@ public final class ChangeMapHandler extends AbstractMaplePacketHandler {
chr.setStance(0);
}
chr.setHp(50);
chr.updatePartyMemberHP();
chr.changeMap(to, to.getRandomPlayerSpawnpoint());
}
} else if (targetid != -1) {

View File

@@ -30,12 +30,17 @@ import tools.data.input.SeekableLittleEndianAccessor;
public final class CharInfoRequestHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.readInt();
slea.skip(4);
int cid = slea.readInt();
MapleMapObject target = c.getPlayer().getMap().getMapObject(cid);
if (target != null) {
if (target instanceof MapleCharacter) {
c.announce(MaplePacketCreator.charInfo((MapleCharacter) target));
MapleCharacter player = (MapleCharacter) target;
if(c.getPlayer().getId() != player.getId()) {
player.exportExcludedItems(c);
}
c.announce(MaplePacketCreator.charInfo(player));
}
}
}

View File

@@ -38,6 +38,11 @@ public class EnterCashShopHandler extends AbstractMaplePacketHandler {
try {
MapleCharacter mc = c.getPlayer();
if (mc.cannotEnterCashShop()) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if (mc.getCashShop().isOpened()) {
return;
}

View File

@@ -22,18 +22,35 @@
package net.server.channel.handlers;
import client.MapleClient;
import client.MapleCharacter;
import client.inventory.MaplePet;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
//import tools.MaplePacketCreator;
/**
* @author BubblesDev
* @author Ronan
*/
public final class PetExcludeItemsHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.readLong();
final int petId = slea.readInt();
slea.skip(4);
MapleCharacter chr = c.getPlayer();
byte petIndex = (byte)chr.getPetIndex(petId);
if (petIndex < 0) return;
final MaplePet pet = chr.getPet(petIndex);
if (pet == null) {
return;
}
chr.resetExcluded(petId);
byte amount = slea.readByte();
for (int i = 0; i < amount; i++) {
c.getPlayer().addExcluded(slea.readInt());
chr.addExcluded(petId, slea.readInt());
}
chr.commitExcludedItems();
}
}

View File

@@ -22,7 +22,6 @@
package net.server.channel.handlers;
import client.MapleCharacter;
import constants.ExpTable;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
@@ -61,7 +60,10 @@ public final class PetFoodHandler extends AbstractMaplePacketHandler {
}
}
}
MaplePet pet = chr.getPet(slot);
if(pet == null) return;
short pos = slea.readShort();
int itemId = slea.readInt();
Item use = chr.getInventory(MapleInventoryType.USE).getItem(pos);

View File

@@ -21,10 +21,14 @@
*/
package net.server.channel.handlers;
import java.util.Set;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import net.AbstractMaplePacketHandler;
import server.maps.MapleMapItem;
import server.maps.MapleMapObject;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -52,6 +56,30 @@ public final class PetLootHandler extends AbstractMaplePacketHandler {
slea.skip(13);
int oid = slea.readInt();
MapleMapObject ob = chr.getMap().getMapObject(oid);
if(ob == null) {
c.getSession().write(MaplePacketCreator.enableActions());
return;
}
if (chr.getInventory(MapleInventoryType.EQUIPPED).findById(1812007) != null) {
final Set<Integer> petIgnore = chr.getExcludedItems();
MapleMapItem mapitem = (MapleMapItem) ob;
if(!petIgnore.isEmpty()) {
if (chr.getInventory(MapleInventoryType.EQUIPPED).findById(1812000) != null) { // Meso magnet
if (mapitem.getMeso() > 0 && petIgnore.contains(Integer.MAX_VALUE)) {
c.getSession().write(MaplePacketCreator.enableActions());
return;
}
} else if (chr.getInventory(MapleInventoryType.EQUIPPED).findById(1812001) != null) { // Item Pouch
if (petIgnore.contains(mapitem.getItem().getItemId())) {
c.getSession().write(MaplePacketCreator.enableActions());
return;
}
}
}
}
chr.pickupItem(ob, petIndex);
}
}

View File

@@ -48,7 +48,6 @@ import client.MapleFamily;
import client.SkillFactory;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import client.inventory.PetDataFactory;
import constants.GameConstants;
import constants.ServerConstants;
@@ -246,7 +245,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
if(newcomer) {
for(MaplePet pet : player.getPets()) {
if(pet != null)
player.startFullnessSchedule(PetDataFactory.getHunger(pet.getItemId()), pet, player.getPetIndex(pet));
world.registerPetHunger(player, player.getPetIndex(pet));
}
player.reloadQuestExpirations();
@@ -261,6 +260,9 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {
player.createDragon();
}
player.commitExcludedItems();
if (newcomer){
/*
if (!c.hasVotedAlready()){
@@ -279,5 +281,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
if(ServerConstants.USE_ADD_RATES_BY_LEVEL == true) player.setPlayerRates();
player.setWorldRates();
player.updateCouponRates();
player.receivePartyMemberHP();
}
}

View File

@@ -94,7 +94,7 @@ public final class ScrollHandler extends AbstractMaplePacketHandler {
if (ItemConstants.isCleanSlate(scroll.getItemId()) && !(toScroll.getLevel() + toScroll.getUpgradeSlots() < ii.getEquipStats(toScroll.getItemId()).get("tuc"))) { //upgrade slots can be over because of hammers
return;
}
Equip scrolled = (Equip) ii.scrollEquipWithId(toScroll, scroll.getItemId(), whiteScroll, c.getPlayer().isGM());
Equip scrolled = (Equip) ii.scrollEquipWithId(toScroll, scroll.getItemId(), whiteScroll, 0, c.getPlayer().isGM());
ScrollResult scrollSuccess = Equip.ScrollResult.FAIL; // fail
if (scrolled == null) {
scrollSuccess = Equip.ScrollResult.CURSE;

View File

@@ -24,15 +24,10 @@ package net.server.channel.handlers;
import client.MapleCharacter;
import java.awt.Point;
import java.io.File;
import java.sql.PreparedStatement;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import client.inventory.PetDataFactory;
import client.SkillFactory;
import java.sql.Connection;
import java.sql.SQLException;
import tools.DatabaseConnection;
import net.AbstractMaplePacketHandler;
import provider.MapleDataProvider;
import provider.MapleDataProviderFactory;
@@ -95,7 +90,8 @@ public final class SpawnPetHandler extends AbstractMaplePacketHandler {
chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showPet(c.getPlayer(), pet, false, false), true);
c.announce(MaplePacketCreator.petStatUpdate(c.getPlayer()));
c.announce(MaplePacketCreator.enableActions());
chr.startFullnessSchedule(PetDataFactory.getHunger(pet.getItemId()), pet, chr.getPetIndex(pet));
chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(pet));
}
}
}

View File

@@ -117,9 +117,6 @@ public final class SpecialMoveHandler extends AbstractMaplePacketHandler {
int gain = lose * (ef.getY() / 100);
chr.setMp(chr.getMp() + gain);
chr.updateSingleStat(MapleStat.MP, chr.getMp());
} else if (skillid == Hermit.FLASH_JUMP) {
slea.skip(2); // always 0? Also 3rd party FJ effect doesn't seem to work, agh!
//chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showBuffeffect(chr.getId(), skillid, chr.getSkillLevel(skillid), (byte)0), false);
} else if (skillid == Priest.DISPEL || skillid == SuperGM.HEAL_PLUS_DISPEL) {
slea.skip((skillid == Priest.DISPEL) ? 10 : 11);
chr.getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showBuffeffect(chr.getId(), skillid, chr.getSkillLevel(skillid)), false);

View File

@@ -85,28 +85,32 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
return;
}
if (damage > 0) {
loseItems = map.getMonsterById(monsteridfrom).getStats().loseItem();
if (loseItems != null) {
MapleInventoryType type;
final int playerpos = player.getPosition().x;
byte d = 1;
Point pos = new Point(0, player.getPosition().y);
for (loseItem loseItem : loseItems) {
type = MapleItemInformationProvider.getInstance().getInventoryType(loseItem.getId());
for (byte b = 0; b < loseItem.getX(); b++) {//LOL?
if (Randomizer.nextInt(101) >= loseItem.getChance()) {
if (player.haveItem(loseItem.getId())) {
pos.x = (int) (playerpos + ((d % 2 == 0) ? (25 * (d + 1) / 2) : -(25 * (d / 2))));
MapleInventoryManipulator.removeById(c, type, loseItem.getId(), 1, false, false);
map.spawnItemDrop(c.getPlayer(), c.getPlayer(), new Item(loseItem.getId(), (short) 0, (short) 1), map.calcDropPos(pos, player.getPosition()), true, true);
d++;
} else {
break;
MapleMonster assaulter = map.getMonsterById(monsteridfrom);
if(assaulter != null) {
loseItems = assaulter.getStats().loseItem();
if (loseItems != null) {
MapleInventoryType type;
final int playerpos = player.getPosition().x;
byte d = 1;
Point pos = new Point(0, player.getPosition().y);
for (loseItem loseItem : loseItems) {
type = MapleItemInformationProvider.getInstance().getInventoryType(loseItem.getId());
for (byte b = 0; b < loseItem.getX(); b++) {//LOL?
if (Randomizer.nextInt(101) >= loseItem.getChance()) {
if (player.haveItem(loseItem.getId())) {
pos.x = (int) (playerpos + ((d % 2 == 0) ? (25 * (d + 1) / 2) : -(25 * (d / 2))));
MapleInventoryManipulator.removeById(c, type, loseItem.getId(), 1, false, false);
map.spawnItemDrop(c.getPlayer(), c.getPlayer(), new Item(loseItem.getId(), (short) 0, (short) 1), map.calcDropPos(pos, player.getPosition()), true, true);
d++;
} else {
break;
}
}
}
}
map.removeMapObject(attacker);
}
map.removeMapObject(attacker);
}
}
} else {

View File

@@ -28,9 +28,11 @@ import client.MapleStat;
import client.Skill;
import client.SkillFactory;
import client.inventory.Equip;
import client.inventory.Equip.ScrollResult;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import client.inventory.ModifyInventory;
import constants.ItemConstants;
import java.sql.SQLException;
@@ -56,7 +58,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter player = c.getPlayer();
final MapleCharacter player = c.getPlayer();
if (System.currentTimeMillis() - player.getLastUsedCashItem() < 3000) {
player.dropMessage(1, "You have used a cash item recently. Wait a moment and try again.");
c.announce(MaplePacketCreator.enableActions());
@@ -514,7 +516,65 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
c.announce(MaplePacketCreator.sendHammerData(equip.getVicious()));
player.forceUpdateItem(equip);
} else if (itemType == 561) { //VEGA'S SPELL
c.announce(MaplePacketCreator.enableActions());
if (slea.readInt() != 1) {
return;
}
final byte eSlot = (byte) slea.readInt();
final Item eitem = c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem(eSlot);
if (slea.readInt() != 2) {
return;
}
final byte uSlot = (byte) slea.readInt();
final Item uitem = c.getPlayer().getInventory(MapleInventoryType.USE).getItem(uSlot);
if (eitem == null || uitem == null) {
return;
}
//should have a check here against PE hacks
Equip toScroll = (Equip) eitem;
if (toScroll.getUpgradeSlots() < 1) {
c.getSession().write(MaplePacketCreator.getInventoryFull());
return;
}
c.getPlayer().toggleBlockCashShop();
final int curlevel = toScroll.getLevel();
c.getSession().write(MaplePacketCreator.sendVegaScroll(0x40));
final Equip scrolled = (Equip) ii.scrollEquipWithId(toScroll, uitem.getItemId(), false, itemId, c.getPlayer().isGM());
c.getSession().write(MaplePacketCreator.sendVegaScroll(scrolled.getLevel() > curlevel ? 0x41 : 0x43));
//opcodes 0x42, 0x44: "this item cannot be used"; 0x39, 0x45: crashes
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, uSlot, (short) 1, false);
remove(c, itemId);
final MapleClient client = c;
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
if(!player.isLoggedin()) return;
player.toggleBlockCashShop();
final List<ModifyInventory> mods = new ArrayList<>();
mods.add(new ModifyInventory(3, scrolled));
mods.add(new ModifyInventory(0, scrolled));
client.announce(MaplePacketCreator.modifyInventory(true, mods));
ScrollResult scrollResult = scrolled.getLevel() > curlevel ? ScrollResult.SUCCESS : ScrollResult.FAIL;
player.getMap().broadcastMessage(MaplePacketCreator.getScrollEffect(player.getId(), scrollResult, false));
if (eSlot < 0 && (scrollResult == ScrollResult.SUCCESS)) {
player.equipChanged();
}
client.getSession().write(MaplePacketCreator.enableActions());
}
}, 1000 * 3);
} else {
System.out.println("NEW CASH ITEM: " + itemType + "\n" + slea.toString());
c.announce(MaplePacketCreator.enableActions());

View File

@@ -33,6 +33,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.HashMap;
@@ -41,7 +42,11 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.Set;
import java.util.HashSet;
import java.util.concurrent.ScheduledFuture;
import server.TimerManager;
import net.server.PetFullnessWorker;
import net.server.MountTirednessWorker;
import net.server.PlayerStorage;
import net.server.Server;
import net.server.channel.Channel;
@@ -49,7 +54,6 @@ import net.server.channel.CharacterIdChannelPair;
import net.server.guild.MapleGuild;
import net.server.guild.MapleGuildCharacter;
import net.server.guild.MapleGuildSummary;
import tools.LogHelper;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
@@ -70,6 +74,14 @@ public class World {
private Map<Integer, MapleGuildSummary> gsStore = new HashMap<>();
private PlayerStorage players = new PlayerStorage();
private Set<Integer> queuedGuilds = new HashSet<>();
private Map<Integer, Byte> activePets = new LinkedHashMap<>();
private ScheduledFuture<?> petsSchedule;
private long petUpdate;
private Map<Integer, Byte> activeMounts = new LinkedHashMap<>();
private ScheduledFuture<?> mountsSchedule;
private long mountUpdate;
public World(int world, int flag, String eventmsg, int exprate, int droprate, int mesorate, int bossdroprate) {
this.id = world;
@@ -81,6 +93,12 @@ public class World {
this.bossdroprate = bossdroprate;
runningPartyId.set(1);
runningMessengerId.set(1);
petUpdate = System.currentTimeMillis();
mountUpdate = petUpdate;
petsSchedule = TimerManager.getInstance().register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000);
mountsSchedule = TimerManager.getInstance().register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000);
}
public List<Channel> getChannels() {
@@ -181,7 +199,7 @@ public class World {
channels.get(chr.getClient().getChannel() - 1).removePlayer(chr);
players.removePlayer(chr.getId());
}
public int getId() {
return id;
}
@@ -657,6 +675,100 @@ public class World {
}
}
}
private static Integer getPetKey(MapleCharacter chr, byte petSlot) { // assuming max 3 pets
return (chr.getId() << 2) + petSlot;
}
public void registerPetHunger(MapleCharacter chr, byte petSlot) {
if(chr.isGM() && ServerConstants.GM_PETS_NEVER_HUNGRY || ServerConstants.PETS_NEVER_HUNGRY) {
return;
}
Integer key = getPetKey(chr, petSlot);
synchronized(activePets) {
byte initProc;
if(System.currentTimeMillis() - petUpdate > 55000) initProc = ServerConstants.PET_EXHAUST_COUNT - 2;
else initProc = ServerConstants.PET_EXHAUST_COUNT - 1;
activePets.put(key, initProc);
}
}
public void unregisterPetHunger(MapleCharacter chr, byte petSlot) {
Integer key = getPetKey(chr, petSlot);
synchronized(activePets) {
activePets.remove(key);
}
}
public void runPetSchedule() {
Map<Integer, Byte> deployedPets;
synchronized(activePets) {
petUpdate = System.currentTimeMillis();
deployedPets = Collections.unmodifiableMap(activePets);
}
for(Map.Entry<Integer, Byte> dp: deployedPets.entrySet()) {
MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey() / 4);
if(chr == null || !chr.isLoggedin()) continue;
Byte dpVal = (byte)(dp.getValue() + 1);
if(dpVal == ServerConstants.PET_EXHAUST_COUNT) {
chr.runFullnessSchedule(dp.getKey() % 4);
dpVal = 0;
}
synchronized(activePets) {
activePets.put(dp.getKey(), dpVal);
}
}
}
public void registerMountHunger(MapleCharacter chr) {
if(chr.isGM() && ServerConstants.GM_PETS_NEVER_HUNGRY || ServerConstants.PETS_NEVER_HUNGRY) {
return;
}
Integer key = chr.getId();
synchronized(activeMounts) {
byte initProc;
if(System.currentTimeMillis() - mountUpdate > 45000) initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 2;
else initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 1;
activeMounts.put(key, initProc);
}
}
public void unregisterMountHunger(MapleCharacter chr) {
Integer key = chr.getId();
synchronized(activeMounts) {
activeMounts.remove(key);
}
}
public void runMountSchedule() {
Map<Integer, Byte> deployedMounts;
synchronized(activeMounts) {
mountUpdate = System.currentTimeMillis();
deployedMounts = Collections.unmodifiableMap(activeMounts);
}
for(Map.Entry<Integer, Byte> dp: deployedMounts.entrySet()) {
MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey());
if(chr == null || !chr.isLoggedin()) continue;
Byte dpVal = (byte)(dp.getValue() + 1);
if(dpVal == ServerConstants.MOUNT_EXHAUST_COUNT) {
chr.runTirednessSchedule();
dpVal = 0;
}
synchronized(activeMounts) {
activeMounts.put(dp.getKey(), dpVal);
}
}
}
public void setServerMessage(String msg) {
for (Channel ch : channels) {
@@ -674,6 +786,17 @@ public class World {
for (Channel ch : getChannels()) {
ch.shutdown();
}
if(petsSchedule != null) {
petsSchedule.cancel(false);
petsSchedule = null;
}
if(mountsSchedule != null) {
mountsSchedule.cancel(false);
mountsSchedule = null;
}
players.disconnectAll();
}
}