Roaring tiger + party EXP fix + Owl leaderboard

Fixed Roaring Tiger messenger effect sticking on the client after the end on the animation. Fixed an issue with party EXP handing to low-level players leech EXP. Fixed party EXP system giving players way too much EXP in some cases. Added Owl item search ranking feature, items most searched can be displayed by the Owl instead of the hard-coded counterpart.
This commit is contained in:
ronancpl
2017-10-20 12:48:49 -02:00
parent 57c29603d1
commit 75e11e1996
54 changed files with 146 additions and 51 deletions

View File

@@ -5293,6 +5293,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if (party != null) {
ret.mpc = party.getMemberById(ret.id);
if (ret.mpc != null) {
ret.mpc = new MaplePartyCharacter(ret);
ret.party = party;
}
}

View File

@@ -93,8 +93,8 @@ public class AutobanManager {
* <code>type</code>:<br>
* 0: HealOverTime<br>
* 1: Pet Food<br>
* 2: ItemMerge<br>
* 3: ItemSort<br>
* 2: InventoryMerge<br>
* 3: InventorySort<br>
* 4: SpecialMove<br>
* 5: UseCatchItem<br>
* 6: Item Drop<br>

View File

@@ -10,7 +10,6 @@ import server.maps.FieldLimit;
* @author Ronan
*/
public class GameConstants {
//public static final int[] OWL_DATA = {2000014, 2000015, 2000016};
public static final int[] OWL_DATA = new int[]{1082002, 2070005, 2070006, 1022047, 1102041, 2044705, 2340000, 2040017, 1092030, 2040804};
// Ronan's rates upgrade system

View File

@@ -48,6 +48,7 @@ public class ServerConstants {
public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour).
public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments.
public static final boolean USE_REFRESH_RANK_MOVE = true;
public static final boolean USE_ENFORCE_OWL_SUGGESTIONS = false;//Forces the Owl of Minerva to always display the defined item array on GameConstants.OWL_DATA instead of the featured by the players.
public static final boolean USE_ENFORCE_UNMERCHABLE_PET = true; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues)
public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster)
public static final boolean USE_ERASE_PERMIT_ON_OPENSHOP = true;//Forces "shop permit" item to be consumed when player deploy his/her player shop.
@@ -63,8 +64,10 @@ public class ServerConstants {
public static final int BOSS_DROP_RATE = 20;
public static final double EQUIP_EXP_RATE = 10.0; //Rate for equipment exp gain, grows linearly. Set 1.0 for default (about 100~200 same-level range mobs killed to pass equip from level 1 to 2).
public static final double PARTY_BONUS_EXP_RATE = 1.0; //Rate for the party exp reward.
public static final double PQ_BONUS_EXP_RATE = 0.5; //Rate for the PQ exp reward.
public static final int PARTY_EXPERIENCE_MOD = 1; //Change for event stuff.
public static final double PQ_BONUS_EXP_MOD = 0.5;
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.
@@ -117,15 +120,19 @@ public class ServerConstants {
public static final byte PET_EXHAUST_COUNT = 3; //Number of proc counts (1 per minute) on the exhaust schedule for fullness.
public static final byte MOUNT_EXHAUST_COUNT = 1; //Number of proc counts (1 per minute) on the exhaust schedule for tiredness.
//Pet Hunger Configuration
public static final boolean PETS_NEVER_HUNGRY = false; //If true, pets and mounts will never grow hungry.
public static final boolean GM_PETS_NEVER_HUNGRY = true; //If true, pets and mounts owned by GMs will never grow hungry.
//Event Configuration
public static final int EVENT_MAX_GUILD_QUEUE = 10; //Max number of guilds in queue for GPQ.
public static final long EVENT_LOBBY_DELAY = 10; //Cooldown duration in seconds before reopening an event lobby.
//Dojo Configuration
public static final boolean USE_DEADLY_DOJO = false; //Should bosses really use 1HP,1MP attacks in dojo?
public static final int DOJO_ENERGY_ATK = 100; //Dojo energy gain when deal attack
public static final int DOJO_ENERGY_DMG = 20; //Dojo energy gain when recv attack
//Pet Hunger Configuration
public static final boolean PETS_NEVER_HUNGRY = false; //If true, pets and mounts will never grow hungry.
public static final boolean GM_PETS_NEVER_HUNGRY = true; //If true, pets and mounts owned by GMs will never grow hungry.
//Event End Timestamp
public static final long EVENT_END_TIMESTAMP = 1428897600000L;

View File

@@ -500,7 +500,7 @@ public final class Channel {
if(dungeons.containsKey(dungeonid)) return false;
MapleMiniDungeonInfo mmdi = MapleMiniDungeonInfo.getDungeon(dungeonid);
MapleMiniDungeon mmd = new MapleMiniDungeon(mmdi.getBase(), 30); // all minidungeons timeouts on 30 mins
MapleMiniDungeon mmd = new MapleMiniDungeon(mmdi.getBase(), 30); // all minidungeons timeout on 30 mins
dungeons.put(dungeonid, mmd);
return true;

View File

@@ -37,6 +37,7 @@ import tools.data.input.SeekableLittleEndianAccessor;
* @author XoticStory
*/
public final class HiredMerchantRequest extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
if (chr.getMap().getMapObjectsInRange(chr.getPosition(), 23000, Arrays.asList(MapleMapObjectType.HIRED_MERCHANT)).isEmpty() && (GameConstants.isFreeMarketRoom(chr.getMapId()))) {

View File

@@ -44,7 +44,6 @@ import tools.Pair;
import tools.data.input.SeekableLittleEndianAccessor;
import client.BuddylistEntry;
import client.CharacterNameAndId;
import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleClient;
import client.MapleFamily;

View File

@@ -34,6 +34,7 @@ import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import client.inventory.ModifyInventory;
import constants.ItemConstants;
import constants.ServerConstants;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -441,6 +442,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
} else if (itemType == 523) {
int itemid = slea.readInt();
if(!ServerConstants.USE_ENFORCE_OWL_SUGGESTIONS) c.getWorldServer().addOwlItemSearch(itemid);
player.setOwlSearch(itemid);
List<Pair<MaplePlayerShopItem, AbstractMapleMapObject>> hmsAvailable = c.getWorldServer().getAvailableItemBundles(itemid);
if(!hmsAvailable.isEmpty()) remove(c, itemId);

View File

@@ -25,11 +25,46 @@ import client.MapleClient;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.MaplePacketCreator;
import tools.Pair;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import constants.GameConstants;
public final class UseOwlOfMinervaHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
c.announce(MaplePacketCreator.getOwlOpen());
List<Pair<Integer, Integer>> owlSearched = c.getWorldServer().getOwlSearchedItems();
List<Integer> owlLeaderboards;
if(owlSearched.size() < 5) {
owlLeaderboards = new LinkedList<>();
for(int i : GameConstants.OWL_DATA) {
owlLeaderboards.add(i);
}
} else {
Comparator<Pair<Integer, Integer>> comparator = new Comparator<Pair<Integer, Integer>>() { // descending order
@Override
public int compare(Pair<Integer, Integer> p1, Pair<Integer, Integer> p2) {
return p2.getRight().compareTo(p1.getRight());
}
};
PriorityQueue<Pair<Integer, Integer>> queue = new PriorityQueue<>(10, comparator);
for(Pair<Integer, Integer> p : owlSearched) {
queue.add(p);
}
owlLeaderboards = new LinkedList<>();
for(int i = 0; i < Math.min(owlSearched.size(), 10); i++) {
owlLeaderboards.add(queue.remove().getLeft());
}
}
c.announce(MaplePacketCreator.getOwlOpen(owlLeaderboards));
}
}

View File

@@ -40,7 +40,10 @@ import java.util.List;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Set;
import java.util.HashSet;
import java.util.concurrent.ScheduledFuture;
@@ -69,6 +72,7 @@ import tools.Pair;
/**
*
* @author kevintjuh93
* @author Ronan (thread-oriented world schedules)
*/
public class World {
@@ -84,6 +88,9 @@ public class World {
private PlayerStorage players = new PlayerStorage();
private Set<Integer> queuedGuilds = new HashSet<>();
private Map<Integer, Integer> owlSearched = new LinkedHashMap<>();
private Lock owlLock = new ReentrantLock();
private Map<Integer, Byte> activePets = new LinkedHashMap<>();
private ScheduledFuture<?> petsSchedule;
private long petUpdate;
@@ -720,6 +727,39 @@ public class World {
return (chr.getId() << 2) + petSlot;
}
public void addOwlItemSearch(Integer itemid) {
owlLock.lock();
try {
Integer cur = owlSearched.get(itemid);
if(cur != null) {
owlSearched.put(itemid, cur + 1);
} else {
owlSearched.put(itemid, 1);
}
} finally {
owlLock.unlock();
}
}
public List<Pair<Integer, Integer>> getOwlSearchedItems() {
if(ServerConstants.USE_ENFORCE_OWL_SUGGESTIONS) {
return new ArrayList<>(0);
}
owlLock.lock();
try {
List<Pair<Integer, Integer>> searchCounts = new ArrayList<>(owlSearched.size());
for(Entry<Integer, Integer> e : owlSearched.entrySet()) {
searchCounts.add(new Pair<>(e.getKey(), e.getValue()));
}
return searchCounts;
} finally {
owlLock.unlock();
}
}
public void registerPetHunger(MapleCharacter chr, byte petSlot) {
if(chr.isGM() && ServerConstants.GM_PETS_NEVER_HUNGRY || ServerConstants.PETS_NEVER_HUNGRY) {
return;

View File

@@ -642,9 +642,9 @@ public class AbstractPlayerInteraction {
public void givePartyExp(String PQ, boolean instance) {
//1 player = 0% bonus (100)
//2 players = 0% bonus (100)
//3 players = +0% bonus (100)
//1 player = +0% bonus (100)
//2 players = +0% bonus (100)
//3 players = +0% bonus (100)
//4 players = +10% bonus (110)
//5 players = +20% bonus (120)
//6 players = +30% bonus (130)
@@ -671,8 +671,8 @@ public class AbstractPlayerInteraction {
int base = PartyQuest.getExp(PQ, player.getLevel());
int exp = base * bonus / 100;
player.gainExp(exp, true, true);
if(ServerConstants.PQ_BONUS_EXP_MOD > 0 && System.currentTimeMillis() <= ServerConstants.EVENT_END_TIMESTAMP) {
player.gainExp((int) (exp * ServerConstants.PQ_BONUS_EXP_MOD), true, true);
if(ServerConstants.PQ_BONUS_EXP_RATE > 0 && System.currentTimeMillis() <= ServerConstants.EVENT_END_TIMESTAMP) {
player.gainExp((int) (exp * ServerConstants.PQ_BONUS_EXP_RATE), true, true);
}
}
}

View File

@@ -33,6 +33,8 @@ import java.util.logging.Logger;
import javax.script.Invocable;
import javax.script.ScriptException;
import constants.ServerConstants;
import client.MapleCharacter;
import net.server.Server;
import net.server.world.World;
import net.server.channel.Channel;
@@ -44,15 +46,14 @@ import server.expeditions.MapleExpedition;
import server.maps.MapleMap;
import server.life.MapleMonster;
import server.life.MapleLifeFactory;
import server.quest.MapleQuest;
import client.MapleCharacter;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import server.quest.MapleQuest;
/**
*
@@ -75,11 +76,9 @@ public class EventManager {
private String name;
private Lock lobbyLock = new ReentrantLock();
private Lock queueLock = new ReentrantLock();
private static final int limitGuilds = 10; // max numbers of guilds in queue for GPQ.
private static final int maxLobbys = 8; // an event manager holds up to this amount of concurrent lobbys
private static final long lobbyDelay = 10; // 10 seconds cooldown before reopening a lobby
private static final int maxLobbys = 8; // an event manager holds up to this amount of concurrent lobbys
public EventManager(Channel cserv, Invocable iv, String name) {
this.server = Server.getInstance();
this.iv = iv;
@@ -107,7 +106,7 @@ public class EventManager {
}
public long getLobbyDelay() {
return lobbyDelay;
return ServerConstants.EVENT_LOBBY_DELAY;
}
private List<Integer> getLobbyRange() {
@@ -128,6 +127,7 @@ public class EventManager {
public ScheduledFuture<?> schedule(final String methodName, final EventInstanceManager eim, long delay) {
return TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
try {
iv.invokeFunction(methodName, eim);
@@ -140,6 +140,7 @@ public class EventManager {
public ScheduledFuture<?> scheduleAtTimestamp(final String methodName, long timestamp) {
return TimerManager.getInstance().scheduleAtTimestamp(new Runnable() {
@Override
public void run() {
try {
iv.invokeFunction(methodName, (Object) null);
@@ -190,7 +191,7 @@ public class EventManager {
freeLobbyInstance(name);
instances.remove(name);
}
}, lobbyDelay * 1000);
}, ServerConstants.EVENT_LOBBY_DELAY * 1000);
}
public void setProperty(String key, String value) {
@@ -561,7 +562,7 @@ public class EventManager {
public boolean isQueueFull() {
synchronized(queuedGuilds) {
return queuedGuilds.size() >= limitGuilds;
return queuedGuilds.size() >= ServerConstants.EVENT_MAX_GUILD_QUEUE;
}
}

View File

@@ -355,18 +355,15 @@ public class MapleInventoryManipulator {
public static void move(MapleClient c, MapleInventoryType type, short src, short dst) {
if (src < 0 || dst < 0) {
System.out.println("src " + src + " dst " + dst);
return;
}
if(dst > c.getPlayer().getInventory(type).getSlotLimit()) {
System.out.println("slim " + c.getPlayer().getInventory(type).getSlotLimit() + " dst " + dst);
return;
}
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
Item source = c.getPlayer().getInventory(type).getItem(src);
Item initialTarget = c.getPlayer().getInventory(type).getItem(dst);
if (source == null) {
System.out.println("null");
return;
}
short olddstQ = -1;

View File

@@ -258,7 +258,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
return takenDamage.containsKey(chr.getId());
}
private void distributeExperienceToParty(int pid, int exp, int killer, Map<Integer, Integer> expDist, Set<MapleCharacter> underleveled) {
private void distributeExperienceToParty(int pid, int exp, int killer, Set<MapleCharacter> underleveled) {
List<MapleCharacter> members = new LinkedList<>();
MapleCharacter pchar = getMap().getAnyCharacterFromParty(pid);
if(pchar != null) {
@@ -290,7 +290,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
for (MapleCharacter mc : members) {
int id = mc.getId();
int level = mc.getLevel();
if (expDist.containsKey(id) || level >= leechMinLevel) {
if (level >= leechMinLevel) {
boolean isKiller = killer == id;
boolean mostDamage = mostDamageCid == id;
int xp = (int) ((0.80f * exp * level) / partyLevel);
@@ -344,7 +344,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
for (Entry<Integer, Integer> party : partyExp.entrySet()) {
distributeExperienceToParty(party.getKey(), party.getValue(), killerId, expDist, underleveled);
distributeExperienceToParty(party.getKey(), party.getValue(), killerId, underleveled);
}
for(MapleCharacter mc : underleveled) {
@@ -358,16 +358,17 @@ public class MapleMonster extends AbstractLoadedMapleLife {
getMap().getEventInstance().monsterKilled(attacker, this);
}
}
final int partyModifier = numExpSharers > 1 ? (110 + (5 * (numExpSharers - 2))) : 0;
//PARTY BONUS: 2p -> +2% , 3p -> +4% , 4p -> +6% , 5p -> +8% , 6p -> +10%
final float partyModifier = numExpSharers <= 1 ? 0.0f : 0.02f * (numExpSharers - 1);
int partyExp = 0;
if (attacker.getHp() > 0) {
int personalExp = exp * attacker.getExpRate();
if (exp > 0) {
if (partyModifier > 0) {
partyExp = (int) (personalExp * ServerConstants.PARTY_EXPERIENCE_MOD * partyModifier / 1000f);
if (partyModifier > 0.0f) {
partyExp = (int) (personalExp * partyModifier * ServerConstants.PARTY_BONUS_EXP_RATE);
}
Integer holySymbol = attacker.getBuffedValue(MapleBuffStat.HOLY_SYMBOL);
boolean GMHolySymbol = attacker.getBuffSource(MapleBuffStat.HOLY_SYMBOL) == SuperGM.HOLY_SYMBOL;

View File

@@ -5019,13 +5019,13 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
public static byte[] getOwlOpen() {
public static byte[] getOwlOpen(List<Integer> owlLeaderboards) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.SHOP_SCANNER_RESULT.getValue());
mplew.write(7);
mplew.write(GameConstants.OWL_DATA.length);
for (int i : GameConstants.OWL_DATA) {
mplew.write(owlLeaderboards.size());
for (Integer i : owlLeaderboards) {
mplew.writeInt(i);
}