Files
sweetgum-server/src/main/java/server/expeditions/MapleExpedition.java
P0nk 8f6860d7d7 All packet creating methods now create Packet instead of byte[]
This commit got way too big...
- Remove deprecated methods for sending packets
- Favor OutPacket & Packet over MaplePacketLittleEndianWriter, LittleEndianWriter, and byte array
- Split up some packet creating methods into separate classes
2021-08-21 01:36:51 +02:00

413 lines
15 KiB
Java

/*
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 server.expeditions;
import client.MapleCharacter;
import net.packet.Packet;
import net.server.PlayerStorage;
import net.server.Server;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import net.server.channel.Channel;
import server.TimerManager;
import server.life.MapleMonster;
import server.maps.MapleMap;
import tools.LogHelper;
import tools.PacketCreator;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;
/**
*
* @author Alan (SharpAceX)
*/
public class MapleExpedition {
private static final int [] EXPEDITION_BOSSES = {
8800000,// - Zakum's first body
8800001,// - Zakum's second body
8800002,// - Zakum's third body
8800003,// - Zakum's Arm 1
8800004,// - Zakum's Arm 2
8800005,// - Zakum's Arm 3
8800006,// - Zakum's Arm 4
8800007,// - Zakum's Arm 5
8800008,// - Zakum's Arm 6
8800009,// - Zakum's Arm 7
8800010,// - Zakum's Arm 8
8810000,// - Horntail's Left Head
8810001,// - Horntail's Right Head
8810002,// - Horntail's Head A
8810003,// - Horntail's Head B
8810004,// - Horntail's Head C
8810005,// - Horntail's Left Hand
8810006,// - Horntail's Right Hand
8810007,// - Horntail's Wings
8810008,// - Horntail's Legs
8810009,// - Horntail's Tails
9420546,// - Scarlion Boss
9420547,// - Scarlion Boss
9420548,// - Angry Scarlion Boss
9420549,// - Furious Scarlion Boss
9420541,// - Targa
9420542,// - Targa
9420543,// - Angry Targa
9420544,// - Furious Targa
};
private MapleCharacter leader;
private MapleExpeditionType type;
private boolean registering;
private MapleMap startMap;
private List<String> bossLogs;
private ScheduledFuture<?> schedule;
private Map<Integer, String> members = new ConcurrentHashMap<>();
private List<Integer> banned = new CopyOnWriteArrayList<>();
private long startTime;
private Properties props = new Properties();
private boolean silent;
private int minSize, maxSize;
private MonitoredReentrantLock pL = MonitoredReentrantLockFactory.createLock(MonitoredLockType.EIM_PARTY, true);
public MapleExpedition(MapleCharacter player, MapleExpeditionType met, boolean sil, int minPlayers, int maxPlayers) {
leader = player;
members.put(player.getId(), player.getName());
startMap = player.getMap();
type = met;
silent = sil;
minSize = (minPlayers != 0) ? minPlayers : type.getMinSize();
maxSize = (maxPlayers != 0) ? maxPlayers : type.getMaxSize();
bossLogs = new CopyOnWriteArrayList<>();
}
public int getMinSize() {
return minSize;
}
public int getMaxSize() {
return maxSize;
}
public void beginRegistration() {
registering = true;
leader.sendPacket(PacketCreator.getClock(type.getRegistrationTime() * 60));
if (!silent) {
startMap.broadcastMessage(leader, PacketCreator.serverNotice(6, "[Expedition] " + leader.getName() + " has been declared the expedition captain. Please register for the expedition."), false);
leader.sendPacket(PacketCreator.serverNotice(6, "[Expedition] You have become the expedition captain. Gather enough people for your team then talk to the NPC to start."));
}
scheduleRegistrationEnd();
}
private void scheduleRegistrationEnd() {
final MapleExpedition exped = this;
startTime = System.currentTimeMillis() + type.getRegistrationTime() * 60 * 1000;
schedule = TimerManager.getInstance().schedule(() -> {
if (registering){
exped.removeChannelExpedition(startMap.getChannelServer());
if (!silent) startMap.broadcastMessage(PacketCreator.serverNotice(6, "[Expedition] The time limit has been reached. Expedition has been disbanded."));
dispose(false);
}
}, type.getRegistrationTime() * 60 * 1000);
}
public void dispose(boolean log) {
broadcastExped(PacketCreator.removeClock());
if (schedule != null) {
schedule.cancel(false);
}
if (log && !registering) {
LogHelper.logExpedition(this);
}
}
public void finishRegistration() {
registering = false;
}
public void start(){
finishRegistration();
registerExpeditionAttempt();
broadcastExped(PacketCreator.removeClock());
if (!silent) broadcastExped(PacketCreator.serverNotice(6, "[Expedition] The expedition has started! Good luck, brave heroes!"));
startTime = System.currentTimeMillis();
Server.getInstance().broadcastGMMessage(startMap.getWorld(), PacketCreator.serverNotice(6, "[Expedition] " + type.toString() + " Expedition started with leader: " + leader.getName()));
}
public String addMember(MapleCharacter player) {
if (!registering){
return "Sorry, this expedition is already underway. Registration is closed!";
}
if (banned.contains(player.getId())){
return "Sorry, you've been banned from this expedition by #b" + leader.getName() + "#k.";
}
if (members.size() >= this.getMaxSize()){ //Would be a miracle if anybody ever saw this
return "Sorry, this expedition is full!";
}
int channel = this.getRecruitingMap().getChannelServer().getId();
if (!MapleExpeditionBossLog.attemptBoss(player.getId(), channel, this, false)) { // thanks Conrad, Cato for noticing some expeditions have entry limit
return "Sorry, you've already reached the quota of attempts for this expedition! Try again another day...";
}
members.put(player.getId(), player.getName());
player.sendPacket(PacketCreator.getClock((int)(startTime - System.currentTimeMillis()) / 1000));
if (!silent) broadcastExped(PacketCreator.serverNotice(6, "[Expedition] " + player.getName() + " has joined the expedition!"));
return "You have registered for the expedition successfully!";
}
public int addMemberInt(MapleCharacter player) {
if (!registering) {
return 1; //"Sorry, this expedition is already underway. Registration is closed!";
}
if (banned.contains(player.getId())) {
return 2; //"Sorry, you've been banned from this expedition by #b" + leader.getName() + "#k.";
}
if (members.size() >= this.getMaxSize()) { //Would be a miracle if anybody ever saw this
return 3; //"Sorry, this expedition is full!";
}
members.put(player.getId(), player.getName());
player.sendPacket(PacketCreator.getClock((int) (startTime - System.currentTimeMillis()) / 1000));
if (!silent) broadcastExped(PacketCreator.serverNotice(6, "[Expedition] " + player.getName() + " has joined the expedition!"));
return 0; //"You have registered for the expedition successfully!";
}
private void registerExpeditionAttempt(){
int channel = this.getRecruitingMap().getChannelServer().getId();
for (MapleCharacter chr : getActiveMembers()){
MapleExpeditionBossLog.attemptBoss(chr.getId(), channel, this, true);
}
}
private void broadcastExped(Packet packet){
for (MapleCharacter chr : getActiveMembers()){
chr.sendPacket(packet);
}
}
public boolean removeMember(MapleCharacter chr) {
if(members.remove(chr.getId()) != null) {
chr.sendPacket(PacketCreator.removeClock());
if (!silent) {
broadcastExped(PacketCreator.serverNotice(6, "[Expedition] " + chr.getName() + " has left the expedition."));
chr.dropMessage(6, "[Expedition] You have left this expedition.");
}
return true;
}
return false;
}
public void ban(Entry<Integer, String> chr) {
int cid = chr.getKey();
if (!banned.contains(cid)) {
banned.add(cid);
members.remove(cid);
if (!silent) broadcastExped(PacketCreator.serverNotice(6, "[Expedition] " + chr.getValue() + " has been banned from the expedition."));
MapleCharacter player = startMap.getWorldServer().getPlayerStorage().getCharacterById(cid);
if (player != null && player.isLoggedinWorld()) {
player.sendPacket(PacketCreator.removeClock());
if (!silent) player.dropMessage(6, "[Expedition] You have been banned from this expedition.");
if (MapleExpeditionType.ARIANT.equals(type) || MapleExpeditionType.ARIANT1.equals(type) || MapleExpeditionType.ARIANT2.equals(type)) {
player.changeMap(980010000);
}
}
}
}
public void monsterKilled(MapleCharacter chr, MapleMonster mob) {
for (int expeditionBoss : EXPEDITION_BOSSES) {
if (mob.getId() == expeditionBoss) { //If the monster killed was a boss
String timeStamp = new SimpleDateFormat("HH:mm:ss").format(new Date());
bossLogs.add(">" + mob.getName() + " was killed after " + LogHelper.getTimeString(startTime) + " - " + timeStamp + "\r\n");
return;
}
}
}
public void setProperty(String key, String value) {
pL.lock();
try {
props.setProperty(key, value);
} finally {
pL.unlock();
}
}
public String getProperty(String key) {
pL.lock();
try {
return props.getProperty(key);
} finally {
pL.unlock();
}
}
public MapleExpeditionType getType() {
return type;
}
public List<MapleCharacter> getActiveMembers() { // thanks MedicOP for figuring out an issue with broadcasting packets to offline members
PlayerStorage ps = startMap.getWorldServer().getPlayerStorage();
List<MapleCharacter> activeMembers = new LinkedList<>();
for (Integer chrid : getMembers().keySet()){
MapleCharacter chr = ps.getCharacterById(chrid);
if (chr != null && chr.isLoggedinWorld()) {
activeMembers.add(chr);
}
}
return activeMembers;
}
public Map<Integer, String> getMembers() {
return new HashMap<>(members);
}
public List<Entry<Integer, String>> getMemberList() {
List<Entry<Integer, String>> memberList = new LinkedList<>();
Entry<Integer, String> leaderEntry = null;
for (Entry<Integer, String> e : getMembers().entrySet()) {
if (!isLeader(e.getKey())) {
memberList.add(e);
} else {
leaderEntry = e;
}
}
if (leaderEntry != null) {
memberList.add(0, leaderEntry);
}
return memberList;
}
public final boolean isExpeditionTeamTogether() {
List<MapleCharacter> chars = getActiveMembers();
if(chars.size() <= 1) return true;
Iterator<MapleCharacter> iterator = chars.iterator();
MapleCharacter mc = iterator.next();
int mapId = mc.getMapId();
for (; iterator.hasNext();) {
mc = iterator.next();
if(mc.getMapId() != mapId) return false;
}
return true;
}
public final void warpExpeditionTeam(int warpFrom, int warpTo) {
List<MapleCharacter> players = getActiveMembers();
for (MapleCharacter chr : players) {
if(chr.getMapId() == warpFrom)
chr.changeMap(warpTo);
}
}
public final void warpExpeditionTeam(int warpTo) {
List<MapleCharacter> players = getActiveMembers();
for (MapleCharacter chr : players) {
chr.changeMap(warpTo);
}
}
public final void warpExpeditionTeamToMapSpawnPoint(int warpFrom, int warpTo, int toSp) {
List<MapleCharacter> players = getActiveMembers();
for (MapleCharacter chr : players) {
if(chr.getMapId() == warpFrom)
chr.changeMap(warpTo, toSp);
}
}
public final void warpExpeditionTeamToMapSpawnPoint(int warpTo, int toSp) {
List<MapleCharacter> players = getActiveMembers();
for (MapleCharacter chr : players) {
chr.changeMap(warpTo, toSp);
}
}
public final boolean addChannelExpedition(Channel ch) {
return ch.addExpedition(this);
}
public final void removeChannelExpedition(Channel ch) {
ch.removeExpedition(this);
}
public MapleCharacter getLeader(){
return leader;
}
public MapleMap getRecruitingMap() {
return startMap;
}
public boolean contains(MapleCharacter player) {
return members.containsKey(player.getId()) || isLeader(player);
}
public boolean isLeader(MapleCharacter player) {
return isLeader(player.getId());
}
public boolean isLeader(int playerid) {
return leader.getId() == playerid;
}
public boolean isRegistering(){
return registering;
}
public boolean isInProgress(){
return !registering;
}
public long getStartTime(){
return startTime;
}
public List<String> getBossLogs(){
return bossLogs;
}
}