/* 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 . */ package server.partyquest.mcpq; import community.MapleParty; import community.MaplePartyCharacter; import handling.channel.ChannelServer; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Random; import packet.creators.CarnivalPackets; import packet.creators.PacketCreator; import packet.transfer.write.OutPacket; import client.player.Player; import client.player.buffs.Disease; import server.life.MobSkill; import server.life.MobSkillFactory; import server.maps.Field; import server.partyquest.mcpq.MCField.MCTeam; /** * * @author Sammy Guergachi */ /** * Provides an interface for Monster Carnival-specific party methods and variables. * * @author s4nta */ public class MCParty { private MapleParty party; private List characters = new ArrayList<>(); private int availCP = 0; private int totalCP = 0; private MCField.MCTeam team = MCField.MCTeam.NONE; private MCField field; private MCParty enemy; public MCParty(MapleParty party) { this.party = party; for (MaplePartyCharacter chr : party.getMembers()) { if (!chr.isOnline()) continue; Player c = ChannelServer.getInstance(chr.getChannel()).getPlayerStorage().getCharacterById(chr.getId()); characters.add(c); } } public int getSize() { return this.characters.size(); } /** * Checks if the underlying MapleParty still exists in the same way it did when it was created. * That is, if there were no players who left the party. * * [MENTION=850422]return[/MENTION] True if the underlying MapleParty still exists in its original format. */ public boolean exists() { Collection members = getMembers(); for (Player chr : members) { if (chr.getParty() == null || chr.getParty() != this.party) { return false; } } return true; } public int getAverageLevel() { int sum = 0, num = 0; for (Player chr : getMembers()) { sum += chr.getLevel(); num += 1; } return sum / num; } public boolean checkLevels() { if (MonsterCarnival.DEBUG) { return true; } for (Player chr : getMembers()) { int lv = chr.getLevel(); if (lv < MonsterCarnival.MIN_LEVEL || lv > MonsterCarnival.MAX_LEVEL) { return false; } } return true; } public boolean checkChannels() { if (MonsterCarnival.DEBUG) { return true; } for (Player chr : getMembers()) { if (chr.getClient().getChannel() != party.getLeader().getChannel()) return false; } return true; } public boolean checkMaps() { if (MonsterCarnival.DEBUG) { return true; } for (Player chr : getMembers()) { if (chr.getMapId() != MonsterCarnival.MAP_LOBBY) return false; } return true; } public void warp(int map) { for (Player chr : getMembers()) { chr.changeMap(map); } } public void warp(Field map) { for (Player chr : getMembers()) { chr.changeMap(map, map.getPortal(0)); } } public void warp(Field map, String portal) { for (Player chr : getMembers()) { chr.changeMap(map, map.getPortal(portal)); } } public void warp(MCField.MCMaps type) { Field m = this.field.getMap(type); for (Player chr : getMembers()) { chr.changeMap(m, m.getPortal(0)); } } public void clock(int secs) { for (Player chr : getMembers()) { chr.getClient().announce(PacketCreator.GetClock(secs)); } } public void notice(String msg) { broadcast(PacketCreator.ServerNotice(6, msg)); } public void broadcast(OutPacket pkt) { for (Player chr : getMembers()) { chr.getClient().announce(pkt); } } /** * Sets MCPQTeam, MCPQParty, and MCPQField for a given character. * [MENTION=2000183830]para[/MENTION]m chr Character to update. */ public void updatePlayer(Player chr) { chr.setMCPQTeam(this.team); chr.setMCPQParty(this); chr.setMCPQField(this.field); } /** * Sets MCPQTeam, MCPQParty, and MCPQ field for all characters in the party. * Unlike deregisterPlayers, this method does NOT warp players to the lobby map. */ public void updatePlayers() { for (Player chr : getMembers()) { this.updatePlayer(chr); } } /** * Resets MCPQ variables for a given character. * [MENTION=2000183830]para[/MENTION]m chr Character to reset. */ public static void deregisterPlayer(Player chr) { chr.setMCPQTeam(MCTeam.NONE); chr.setMCPQParty(null); chr.setMCPQField(null); chr.setAvailableCP(0); chr.setTotalCP(0); } /** * Resets MCPQ variables for all characters in the party. * Unlike updatePlayers, this method DOES warp players to the lobby map. */ public void deregisterPlayers() { for (Player chr : getMembers()) { MCParty.deregisterPlayer(chr); chr.changeMap(MonsterCarnival.MAP_EXIT); } } public void removePlayer(Player chr) { characters.remove(chr); deregisterPlayer(chr); } public void startBattle() { for (Player chr : characters) { chr.getClient().getSession().write(CarnivalPackets.StartMonsterCarnival(chr)); } } /** * Uses some amount of available CP. * [MENTION=2000183830]para[/MENTION]m use A positive integer to be subtracted from available CP. */ public void loseCP(int use) { // TODO: locks? if (use < 0) { System.err.println("Attempting to use negative CP."); } this.availCP -= use; } public void gainCP(int gain) { // TODO: locks? this.availCP += gain; this.totalCP += gain; } public MCParty getEnemy() { return enemy; } public void setEnemy(MCParty enemy) { this.enemy = enemy; } /** * Applies a MCSkill to the entire team. This is used on the team's own players * because it is called when the enemy team uses a debuff/cube of darkness. * [MENTION=2000183830]para[/MENTION]m skill Skill to apply. * [MENTION=850422]return[/MENTION] True if skill was applied, false otherwise. */ public boolean applyMCSkill(MCSkill skill) { MobSkill s = MobSkillFactory.getMobSkill(skill.getMobSkillID(), skill.getLevel()); Disease disease = Disease.getType(skill.getMobSkillID()); if (disease == null) { disease = Disease.DARKNESS; s = MobSkillFactory.getMobSkill(121, 6); // HACK: darkness } else if (disease == Disease.POISON) { return false; } // We only target players on the battlefield map. if (skill.getTarget() == 2) { for (Player chr : getMembers()) { if (MonsterCarnival.isBattlefieldMap(chr.getMapId())) { chr.giveDebuff(disease, s); } } return true; } else { if (getRandomMember() != null) { getRandomMember().giveDebuff(disease, 1, 30000L, disease.getDisease(), 1); return true; } else { return false; } } } public void setField(MCField field) { this.field = field; } public void setTeam(MCTeam newTeam) { this.team = newTeam; } public MCTeam getTeam() { return team; } /** * Returns a collection of online members in the party. * [MENTION=850422]return[/MENTION] Online MCParty members. */ public Collection getMembers() { return this.characters; } public Player getRandomMember() { List chrsOnMap = new ArrayList<>(); for (Player chr : this.characters) { if (MonsterCarnival.isBattlefieldMap(chr.getMapId())) { chrsOnMap.add(chr); } } if (chrsOnMap.isEmpty()) { return null; } return chrsOnMap.get(new Random().nextInt(chrsOnMap.size())); } public int getAvailableCP() { return availCP; } public int getTotalCP() { return totalCP; } }