package handling.world.guild;
import client.MapleCharacter;
import client.MapleCharacterUtil;
import client.MapleClient;
import client.SkillFactory;
import constants.GameConstants;
import database.DatabaseConnection;
import handling.world.World;
import handling.world.guild.MapleBBSThread.MapleBBSReply;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import server.MapleStatEffect;
import tools.data.MaplePacketLittleEndianWriter;
import tools.packet.CField;
import tools.packet.CWvsContext;
import tools.packet.CWvsContext.AlliancePacket;
import tools.packet.CWvsContext.GuildPacket;
import tools.packet.CWvsContext.InfoPacket;
public class MapleGuild implements java.io.Serializable {
private static enum BCOp {
NONE, DISBAND, EMBELMCHANGE
}
public static final long serialVersionUID = 6322150443228168192L;
private final List<MapleGuildCharacter> members = new CopyOnWriteArrayList<>();
private final Map<Integer, MapleGuildSkill> guildSkills = new HashMap<>();
private final String rankTitles[] = new String[5]; // 1 = master, 2 = jr, 5 = lowest member
private String name, notice;
private int id, gp, logo, logoColor, leader, capacity, logoBG, logoBGColor, signature, level;
private boolean bDirty = true, proper = true;
private int allianceid = 0, invitedid = 0;
private final Map<Integer, MapleBBSThread> bbs = new HashMap<>();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private boolean init = false, changed = false, changed_skills = false;
public MapleGuild(final int guildid) {
this(guildid, null);
}
public MapleGuild(final int guildid, Map<Integer, Map<Integer, MapleBBSReply>> replies) {
super();
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM guilds WHERE guildid = ?");
ps.setInt(1, guildid);
ResultSet rs = ps.executeQuery();
if (!rs.first()) {
rs.close();
ps.close();
id = -1;
return;
}
id = guildid;
name = rs.getString("name");
gp = rs.getInt("GP");
logo = rs.getInt("logo");
logoColor = rs.getInt("logoColor");
logoBG = rs.getInt("logoBG");
logoBGColor = rs.getInt("logoBGColor");
capacity = rs.getInt("capacity");
rankTitles[0] = rs.getString("rank1title");
rankTitles[1] = rs.getString("rank2title");
rankTitles[2] = rs.getString("rank3title");
rankTitles[3] = rs.getString("rank4title");
rankTitles[4] = rs.getString("rank5title");
leader = rs.getInt("leader");
notice = rs.getString("notice");
signature = rs.getInt("signature");
allianceid = rs.getInt("alliance");
rs.close();
ps.close();
MapleGuildAlliance alliance = World.Alliance.getAlliance(allianceid);
if (alliance == null) {
allianceid = 0;
}
ps = con.prepareStatement("SELECT id, name, level, job, guildrank, guildContribution, alliancerank FROM characters WHERE guildid = ? ORDER BY guildrank ASC, name ASC", ResultSet.CONCUR_UPDATABLE);
ps.setInt(1, guildid);
rs = ps.executeQuery();
if (!rs.first()) {
System.err.println("No members in guild " + id + ". Impossible... guild is disbanding");
rs.close();
ps.close();
writeToDB(true);
proper = false;
return;
}
boolean leaderCheck = false;
byte gFix = 0, aFix = 0;
do {
int cid = rs.getInt("id");
byte gRank = rs.getByte("guildrank"), aRank = rs.getByte("alliancerank");
if (cid == leader) {
leaderCheck = true;
if (gRank != 1) { //needs updating to 1
gRank = 1;
gFix = 1;
}
if (alliance != null) {
if (alliance.getLeaderId() == cid && aRank != 1) {
aRank = 1;
aFix = 1;
} else if (alliance.getLeaderId() != cid && aRank != 2) {
aRank = 2;
aFix = 2;
}
}
} else {
if (gRank == 1) {
gRank = 2;
gFix = 2;
}
if (aRank < 3) {
aRank = 3;
aFix = 3;
}
}
members.add(new MapleGuildCharacter(cid, rs.getShort("level"), rs.getString("name"), (byte) -1, rs.getInt("job"), gRank, rs.getInt("guildContribution"), aRank, guildid, false));
} while (rs.next());
rs.close();
ps.close();
if (!leaderCheck) {
System.err.println("Leader " + leader + " isn't in guild " + id + ". Impossible... guild is disbanding.");
writeToDB(true);
proper = false;
return;
}
if (gFix > 0) {
ps = con.prepareStatement("UPDATE characters SET guildrank = ? WHERE id = ?");
ps.setByte(1, gFix);
ps.setInt(2, leader);
ps.executeUpdate();
ps.close();
}
if (aFix > 0) {
ps = con.prepareStatement("UPDATE characters SET alliancerank = ? WHERE id = ?");
ps.setByte(1, aFix);
ps.setInt(2, leader);
ps.executeUpdate();
ps.close();
}
ps = con.prepareStatement("SELECT * FROM bbs_threads WHERE guildid = ? ORDER BY localthreadid DESC");
ps.setInt(1, guildid);
rs = ps.executeQuery();
while (rs.next()) {
final int tID = rs.getInt("localthreadid");
final MapleBBSThread thread = new MapleBBSThread(tID, rs.getString("name"), rs.getString("startpost"), rs.getLong("timestamp"),
guildid, rs.getInt("postercid"), rs.getInt("icon"));
if (replies != null && replies.containsKey(rs.getInt("threadid"))) {
thread.replies.putAll(replies.get(rs.getInt("threadid")));
}
bbs.put(tID, thread);
}
rs.close();
ps.close();
ps = con.prepareStatement("SELECT * FROM guildskills WHERE guildid = ?");
ps.setInt(1, guildid);
rs = ps.executeQuery();
while (rs.next()) {
int sid = rs.getInt("skillid");
if (sid < 91000000) { //hack
rs.close();
ps.close();
System.err.println("Skill " + sid + " is in guild " + id + ". Impossible... guild is disbanding.");
writeToDB(true);
proper = false;
return;
}
guildSkills.put(sid, new MapleGuildSkill(sid, rs.getInt("level"), rs.getLong("timestamp"), rs.getString("purchaser"), "")); //activators not saved
}
rs.close();
ps.close();
level = calculateLevel();
} catch (SQLException se) {
System.err.println("unable to read guild information from sql");
}
}
public boolean isProper() {
return proper;
}
public static final void loadAll() {
Map<Integer, Map<Integer, MapleBBSReply>> replies = new LinkedHashMap<>();
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM bbs_replies");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
final int tID = rs.getInt("threadid");
Map<Integer, MapleBBSReply> reply = replies.get(tID);
if (reply == null) {
reply = new HashMap<>();
replies.put(tID, reply);
}
reply.put(reply.size(), new MapleBBSReply(reply.size(), rs.getInt("postercid"), rs.getString("content"), rs.getLong("timestamp")));
}
rs.close();
ps.close();
ps = con.prepareStatement("SELECT guildid FROM guilds");
rs = ps.executeQuery();
while (rs.next()) {
World.Guild.addLoadedGuild(new MapleGuild(rs.getInt("guildid"), replies));
}
rs.close();
ps.close();
} catch (SQLException se) {
System.err.println("unable to read guild information from sql");
}
}
public static final void loadAll(Object toNotify) {
Map<Integer, Map<Integer, MapleBBSReply>> replies = new LinkedHashMap<>();
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM bbs_replies");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
final int tID = rs.getInt("threadid");
Map<Integer, MapleBBSReply> reply = replies.get(tID);
if (reply == null) {
reply = new HashMap<>();
replies.put(tID, reply);
}
reply.put(reply.size(), new MapleBBSReply(reply.size(), rs.getInt("postercid"), rs.getString("content"), rs.getLong("timestamp")));
}
rs.close();
ps.close();
boolean cont = false;
ps = con.prepareStatement("SELECT guildid FROM guilds");
rs = ps.executeQuery();
while (rs.next()) {
GuildLoad.QueueGuildForLoad(rs.getInt("guildid"), replies);
cont = true;
}
rs.close();
ps.close();
if (!cont) {
return;
}
} catch (SQLException se) {
System.err.println("unable to read guild information from sql");
}
AtomicInteger FinishedThreads = new AtomicInteger(0);
GuildLoad.Execute(toNotify);
synchronized (toNotify) {
try {
toNotify.wait();
} catch (InterruptedException ex) {
}
}
while (FinishedThreads.incrementAndGet() != GuildLoad.NumSavingThreads) {
synchronized (toNotify) {
try {
toNotify.wait();
} catch (InterruptedException ex) {
}
}
}
}
public final void writeToDB(final boolean bDisband) {
try {
Connection con = DatabaseConnection.getConnection();
if (!bDisband) {
StringBuilder buf = new StringBuilder("UPDATE guilds SET GP = ?, logo = ?, logoColor = ?, logoBG = ?, logoBGColor = ?, ");
for (int i = 1; i < 6; i++) {
buf.append("rank").append(i).append("title = ?, ");
}
buf.append("capacity = ?, notice = ?, alliance = ?, leader = ? WHERE guildid = ?");
PreparedStatement ps = con.prepareStatement(buf.toString());
ps.setInt(1, gp);
ps.setInt(2, logo);
ps.setInt(3, logoColor);
ps.setInt(4, logoBG);
ps.setInt(5, logoBGColor);
ps.setString(6, rankTitles[0]);
ps.setString(7, rankTitles[1]);
ps.setString(8, rankTitles[2]);
ps.setString(9, rankTitles[3]);
ps.setString(10, rankTitles[4]);
ps.setInt(11, capacity);
ps.setString(12, notice);
ps.setInt(13, allianceid);
ps.setInt(14, leader);
ps.setInt(15, id);
ps.executeUpdate();
ps.close();
if (changed) {
ps = con.prepareStatement("DELETE FROM bbs_threads WHERE guildid = ?");
ps.setInt(1, id);
ps.execute();
ps.close();
ps = con.prepareStatement("DELETE FROM bbs_replies WHERE guildid = ?");
ps.setInt(1, id);
ps.execute();
ps.close();
try (PreparedStatement pse = con.prepareStatement("INSERT INTO bbs_replies (`threadid`, `postercid`, `timestamp`, `content`, `guildid`) VALUES (?, ?, ?, ?, ?)")) {
ps = con.prepareStatement("INSERT INTO bbs_threads(`postercid`, `name`, `timestamp`, `icon`, `startpost`, `guildid`, `localthreadid`) VALUES(?, ?, ?, ?, ?, ?, ?)", DatabaseConnection.RETURN_GENERATED_KEYS);
ps.setInt(6, id);
for (MapleBBSThread bb : bbs.values()) {
ps.setInt(1, bb.ownerID);
ps.setString(2, bb.name);
ps.setLong(3, bb.timestamp);
ps.setInt(4, bb.icon);
ps.setString(5, bb.text);
ps.setInt(7, bb.localthreadID);
ps.execute();
final int ourId;
try (ResultSet rs = ps.getGeneratedKeys()) {
if (!rs.next()) {
rs.close();
continue;
} ourId = rs.getInt(1);
}
pse.setInt(5, id);
for (MapleBBSReply r : bb.replies.values()) {
pse.setInt(1, ourId);
pse.setInt(2, r.ownerID);
pse.setLong(3, r.timestamp);
pse.setString(4, r.content);
pse.addBatch();
}
}
pse.executeBatch();
}
ps.close();
}
if (changed_skills) {
ps = con.prepareStatement("DELETE FROM guildskills WHERE guildid = ?");
ps.setInt(1, id);
ps.execute();
ps.close();
ps = con.prepareStatement("INSERT INTO guildskills(`guildid`, `skillid`, `level`, `timestamp`, `purchaser`) VALUES(?, ?, ?, ?, ?)");
ps.setInt(1, id);
for (MapleGuildSkill i : guildSkills.values()) {
ps.setInt(2, i.skillID);
ps.setByte(3, (byte) i.level);
ps.setLong(4, i.timestamp);
ps.setString(5, i.purchaser);
ps.execute();
}
ps.close();
}
changed_skills = false;
changed = false;
} else {
PreparedStatement ps = con.prepareStatement("DELETE FROM bbs_threads WHERE guildid = ?");
ps.setInt(1, id);
ps.execute();
ps.close();
ps = con.prepareStatement("DELETE FROM bbs_replies WHERE guildid = ?");
ps.setInt(1, id);
ps.execute();
ps.close();
ps = con.prepareStatement("DELETE FROM guildskills WHERE guildid = ?");
ps.setInt(1, id);
ps.execute();
ps.close();
ps = con.prepareStatement("DELETE FROM guilds WHERE guildid = ?");
ps.setInt(1, id);
ps.executeUpdate();
ps.close();
if (allianceid > 0) {
final MapleGuildAlliance alliance = World.Alliance.getAlliance(allianceid);
if (alliance != null) {
alliance.removeGuild(id, false);
}
}
broadcast(GuildPacket.guildDisband(id));
}
} catch (SQLException se) {
System.err.println("Error saving guild to SQL");
}
}
public final int getId() {
return id;
}
public final int getLeaderId() {
return leader;
}
public final MapleCharacter getLeader(final MapleClient c) {
return c.getChannelServer().getPlayerStorage().getCharacterById(leader);
}
public final int getGP() {
return gp;
}
public final int getLogo() {
return logo;
}
public final void setLogo(final int l) {
logo = l;
}
public final int getLogoColor() {
return logoColor;
}
public final void setLogoColor(final int c) {
logoColor = c;
}
public final int getLogoBG() {
return logoBG;
}
public final void setLogoBG(final int bg) {
logoBG = bg;
}
public final int getLogoBGColor() {
return logoBGColor;
}
public final void setLogoBGColor(final int c) {
logoBGColor = c;
}
public final String getNotice() {
if (notice == null) {
return "";
}
return notice;
}
public final String getName() {
return name;
}
public final int getCapacity() {
return capacity;
}
public final int getSignature() {
return signature;
}
public final void broadcast(final byte[] packet) {
broadcast(packet, -1, BCOp.NONE);
}
public final void broadcast(final byte[] packet, final int exception) {
broadcast(packet, exception, BCOp.NONE);
}
// multi-purpose function that reaches every member of guild (except the character with exceptionId) in all channels with as little access to rmi as possible
public final void broadcast(final byte[] packet, final int exceptionId, final BCOp bcop) {
lock.writeLock().lock();
try {
buildNotifications();
} finally {
lock.writeLock().unlock();
}
lock.readLock().lock();
try {
for (MapleGuildCharacter mgc : members) {
if (bcop == BCOp.DISBAND) {
if (mgc.isOnline()) {
World.Guild.setGuildAndRank(mgc.getId(), 0, 5, 0, 5);
} else {
setOfflineGuildStatus(0, (byte) 5, 0, (byte) 5, mgc.getId());
}
} else if (mgc.isOnline() && mgc.getId() != exceptionId) {
if (bcop == BCOp.EMBELMCHANGE) {
World.Guild.changeEmblem(id, mgc.getId(), this);
} else {
World.Broadcast.sendGuildPacket(mgc.getId(), packet, exceptionId, id);
}
}
}
} finally {
lock.readLock().unlock();
}
}
private void buildNotifications() {
if (!bDirty) {
return;
}
final List<Integer> mem = new LinkedList<>();
final Iterator<MapleGuildCharacter> toRemove = members.iterator();
while (toRemove.hasNext()) {
MapleGuildCharacter mgc = toRemove.next();
if (!mgc.isOnline()) {
continue;
}
if (mem.contains(mgc.getId()) || mgc.getGuildId() != id) {
members.remove(mgc);
continue;
}
mem.add(mgc.getId());
}
bDirty = false;
}
public final void setOnline(final int cid, final boolean online, final int channel) {
boolean bBroadcast = true;
for (MapleGuildCharacter mgc : members) {
if (mgc.getGuildId() == id && mgc.getId() == cid) {
if (mgc.isOnline() == online) {
bBroadcast = false;
}
mgc.setOnline(online);
mgc.setChannel((byte) channel);
break;
}
}
if (bBroadcast) {
broadcast(GuildPacket.guildMemberOnline(id, cid, online), cid);
if (allianceid > 0) {
World.Alliance.sendGuild(AlliancePacket.allianceMemberOnline(allianceid, id, cid, online), id, allianceid);
}
}
bDirty = true; // member formation has changed, update notifications
init = true;
}
public final void guildChat(final String name, final int cid, final String msg) {
broadcast(CField.multiChat(name, msg, 2), cid);
}
public final void allianceChat(final String name, final int cid, final String msg) {
broadcast(CField.multiChat(name, msg, 3), cid);
}
public final String getRankTitle(final int rank) {
return rankTitles[rank - 1];
}
public int getAllianceId() {
//return alliance.getId();
return this.allianceid;
}
public int getInvitedId() {
return this.invitedid;
}
public void setInvitedId(int iid) {
this.invitedid = iid;
}
public void setAllianceId(int a) {
this.allianceid = a;
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("UPDATE guilds SET alliance = ? WHERE guildid = ?")) {
ps.setInt(1, a);
ps.setInt(2, id);
ps.execute();
}
} catch (SQLException e) {
System.err.println("Saving allianceid ERROR" + e);
}
}
// function to create guild, returns the guild id if successful, 0 if not
public static final int createGuild(final int leaderId, final String name) {
if (name.length() > 12) {
return 0;
}
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT guildid FROM guilds WHERE name = ?");
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
if (rs.first()) {// name taken
rs.close();
ps.close();
return 0;
}
ps.close();
rs.close();
ps = con.prepareStatement("INSERT INTO guilds (`leader`, `name`, `signature`, `alliance`) VALUES (?, ?, ?, 0)", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, leaderId);
ps.setString(2, name);
ps.setInt(3, (int) (System.currentTimeMillis() / 1000));
ps.executeUpdate();
rs = ps.getGeneratedKeys();
int ret = 0;
if (rs.next()) {
ret = rs.getInt(1);
}
rs.close();
ps.close();
return ret;
} catch (SQLException se) {
System.err.println("SQL THROW");
return 0;
}
}
public final int addGuildMember(final MapleGuildCharacter mgc) {
// first of all, insert it into the members keeping alphabetical order of lowest ranks ;)
lock.writeLock().lock();
try {
if (members.size() >= capacity) {
return 0;
}
for (int i = members.size() - 1; i >= 0; i--) {
if (members.get(i).getGuildRank() < 5 || members.get(i).getName().compareTo(mgc.getName()) < 0) {
members.add(i + 1, mgc);
bDirty = true;
break;
}
}
} finally {
lock.writeLock().unlock();
}
gainGP(500, true, mgc.getId());
broadcast(GuildPacket.newGuildMember(mgc));
if (allianceid > 0) {
World.Alliance.sendGuild(allianceid);
}
return 1;
}
public final void leaveGuild(final MapleGuildCharacter mgc) {
lock.writeLock().lock();
try {
final Iterator<MapleGuildCharacter> itr = members.iterator();
while (itr.hasNext()) {
final MapleGuildCharacter mgcc = itr.next();
if (mgcc.getId() == mgc.getId()) {
broadcast(GuildPacket.memberLeft(mgcc, true));
bDirty = true;
gainGP(mgcc.getGuildContribution() > 0 ? -mgcc.getGuildContribution() : -50);
members.remove(mgcc);
if (mgc.isOnline()) {
World.Guild.setGuildAndRank(mgcc.getId(), 0, 5, 0, 5);
} else {
setOfflineGuildStatus((short) 0, (byte) 5, 0, (byte) 5, mgcc.getId());
}
break;
}
}
} finally {
lock.writeLock().unlock();
}
if (bDirty && allianceid > 0) {
World.Alliance.sendGuild(allianceid);
}
}
public final void expelMember(final MapleGuildCharacter initiator, final String name, final int cid) {
lock.writeLock().lock();
try {
final Iterator<MapleGuildCharacter> itr = members.iterator();
while (itr.hasNext()) {
final MapleGuildCharacter mgc = itr.next();
if (mgc.getId() == cid && initiator.getGuildRank() < mgc.getGuildRank()) {
broadcast(GuildPacket.memberLeft(mgc, true));
bDirty = true;
gainGP(mgc.getGuildContribution() > 0 ? -mgc.getGuildContribution() : -50);
if (mgc.isOnline()) {
World.Guild.setGuildAndRank(cid, 0, 5, 0, 5);
} else {
MapleCharacterUtil.sendNote(mgc.getName(), initiator.getName(), "You have been expelled from the guild.", 0);
setOfflineGuildStatus((short) 0, (byte) 5, 0, (byte) 5, cid);
}
members.remove(mgc);
break;
}
}
} finally {
lock.writeLock().unlock();
}
if (bDirty && allianceid > 0) {
World.Alliance.sendGuild(allianceid);
}
}
public final void changeARank() {
changeARank(false);
}
public final void changeARank(final boolean leader) {
if (allianceid <= 0) {
return;
}
for (final MapleGuildCharacter mgc : members) {
byte newRank = 3;
if (this.leader == mgc.getId()) {
newRank = (byte) (leader ? 1 : 2);
}
if (mgc.isOnline()) {
World.Guild.setGuildAndRank(mgc.getId(), this.id, mgc.getGuildRank(), mgc.getGuildContribution(), newRank);
} else {
setOfflineGuildStatus(this.id, (byte) mgc.getGuildRank(), mgc.getGuildContribution(), (byte) newRank, mgc.getId());
}
mgc.setAllianceRank((byte) newRank);
}
World.Alliance.sendGuild(allianceid);
}
public final void changeARank(final int newRank) {
if (allianceid <= 0) {
return;
}
for (final MapleGuildCharacter mgc : members) {
if (mgc.isOnline()) {
World.Guild.setGuildAndRank(mgc.getId(), this.id, mgc.getGuildRank(), mgc.getGuildContribution(), newRank);
} else {
setOfflineGuildStatus(this.id, (byte) mgc.getGuildRank(), mgc.getGuildContribution(), (byte) newRank, mgc.getId());
}
mgc.setAllianceRank((byte) newRank);
}
World.Alliance.sendGuild(allianceid);
}
public final boolean changeARank(final int cid, final int newRank) {
if (allianceid <= 0) {
return false;
}
for (final MapleGuildCharacter mgc : members) {
if (cid == mgc.getId()) {
if (mgc.isOnline()) {
World.Guild.setGuildAndRank(cid, this.id, mgc.getGuildRank(), mgc.getGuildContribution(), newRank);
} else {
setOfflineGuildStatus(this.id, (byte) mgc.getGuildRank(), mgc.getGuildContribution(), (byte) newRank, cid);
}
mgc.setAllianceRank((byte) newRank);
World.Alliance.sendGuild(allianceid);
return true;
}
}
return false;
}
public final void changeGuildLeader(final int cid) {
if (changeRank(cid, 1) && changeRank(leader, 2)) {
if (allianceid > 0) {
int aRank = getMGC(leader).getAllianceRank();
if (aRank == 1) {
World.Alliance.changeAllianceLeader(allianceid, cid, true);
} else {
changeARank(cid, aRank);
}
changeARank(leader, 3);
}
broadcast(GuildPacket.guildLeaderChanged(id, leader, cid, allianceid));
this.leader = cid;
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("UPDATE guilds SET leader = ? WHERE guildid = ?")) {
ps.setInt(1, cid);
ps.setInt(2, id);
ps.execute();
}
} catch (SQLException e) {
System.err.println("Saving leaderid ERROR" + e);
}
}
}
public final boolean changeRank(final int cid, final int newRank) {
for (final MapleGuildCharacter mgc : members) {
if (cid == mgc.getId()) {
if (mgc.isOnline()) {
World.Guild.setGuildAndRank(cid, this.id, newRank, mgc.getGuildContribution(), mgc.getAllianceRank());
} else {
setOfflineGuildStatus(this.id, (byte) newRank, mgc.getGuildContribution(), (byte) mgc.getAllianceRank(), cid);
}
mgc.setGuildRank((byte) newRank);
broadcast(GuildPacket.changeRank(mgc));
return true;
}
}
// it should never get to this point unless cid was incorrect o_O
return false;
}
public final void setGuildNotice(final String notice) {
this.notice = notice;
broadcast(GuildPacket.guildNotice(id, notice));
}
public final void memberLevelJobUpdate(final MapleGuildCharacter mgc) {
for (final MapleGuildCharacter member : members) {
if (member.getId() == mgc.getId()) {
int old_level = member.getLevel();
int old_job = member.getJobId();
member.setJobId(mgc.getJobId());
member.setLevel((short) mgc.getLevel());
if (mgc.getLevel() > old_level) {
gainGP((mgc.getLevel() - old_level) * mgc.getLevel(), false, mgc.getId());
//aftershock: formula changes (below 100 = 40, above 100 = 80) (12000 max) but i prefer level (21100 max), add guildContribution, do setGuildAndRank or just get the MapleCharacter object
}
if (old_level != mgc.getLevel()) {
this.broadcast(CWvsContext.sendLevelup(false, mgc.getLevel(), mgc.getName()), mgc.getId());
}
if (old_job != mgc.getJobId()) {
this.broadcast(CWvsContext.sendJobup(false, mgc.getJobId(), mgc.getName()), mgc.getId());
}
broadcast(GuildPacket.guildMemberLevelJobUpdate(mgc));
if (allianceid > 0) {
World.Alliance.sendGuild(AlliancePacket.updateAlliance(mgc, allianceid), id, allianceid);
}
break;
}
}
}
public final void changeRankTitle(final String[] ranks) {
System.arraycopy(ranks, 0, rankTitles, 0, 5);
broadcast(GuildPacket.rankTitleChange(id, ranks));
}
public final void disbandGuild() {
writeToDB(true);
broadcast(null, -1, BCOp.DISBAND);
}
public final void setGuildEmblem(final short bg, final byte bgcolor, final short logo, final byte logocolor) {
this.logoBG = bg;
this.logoBGColor = bgcolor;
this.logo = logo;
this.logoColor = logocolor;
broadcast(null, -1, BCOp.EMBELMCHANGE);
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("UPDATE guilds SET logo = ?, logoColor = ?, logoBG = ?, logoBGColor = ? WHERE guildid = ?")) {
ps.setInt(1, logo);
ps.setInt(2, logoColor);
ps.setInt(3, logoBG);
ps.setInt(4, logoBGColor);
ps.setInt(5, id);
ps.execute();
}
} catch (SQLException e) {
System.err.println("Saving guild logo / BG colo ERROR");
}
}
public final MapleGuildCharacter getMGC(final int cid) {
for (final MapleGuildCharacter mgc : members) {
if (mgc.getId() == cid) {
return mgc;
}
}
return null;
}
public final boolean increaseCapacity(boolean trueMax) {
if (capacity >= (trueMax ? 200 : 100) || ((capacity + 5) > (trueMax ? 200 : 100))) {
return false;
}
if (trueMax && gp < 25000) {
return false;
}
if (trueMax && gp - 25000 < GameConstants.getGuildExpNeededForLevel(getLevel() - 1)) {
return false;
}
capacity += 5;
broadcast(GuildPacket.guildCapacityChange(this.id, this.capacity));
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("UPDATE guilds SET capacity = ? WHERE guildid = ?")) {
ps.setInt(1, this.capacity);
ps.setInt(2, this.id);
ps.execute();
}
} catch (SQLException e) {
System.err.println("Saving guild capacity ERROR");
}
return true;
}
public final void gainGP(final int amount) {
gainGP(amount, true, -1);
}
public final void gainGP(int amount, final boolean broadcast) {
gainGP(amount, broadcast, -1);
}
public final void gainGP(int amount, final boolean broadcast, final int cid) {
if (amount == 0) { //no change, no broadcast and no sql.
return;
}
if (amount + gp < 0) {
amount = -gp;
} //0 lowest
if (cid > 0 && amount > 0) {
final MapleGuildCharacter mg = getMGC(cid);
if (mg != null) {
mg.setGuildContribution(mg.getGuildContribution() + amount);
if (mg.isOnline()) {
World.Guild.setGuildAndRank(cid, this.id, mg.getGuildRank(), mg.getGuildContribution(), mg.getAllianceRank());
} else {
setOfflineGuildStatus(this.id, (byte) mg.getGuildRank(), mg.getGuildContribution(), (byte) mg.getAllianceRank(), cid);
}
broadcast(GuildPacket.guildContribution(id, cid, mg.getGuildContribution()));
}
}
gp += amount;
level = calculateLevel();
broadcast(GuildPacket.updateGP(id, gp, level));
if (broadcast) {
broadcast(InfoPacket.getGPMsg(amount));
}
}
public Collection<MapleGuildSkill> getSkills() {
return guildSkills.values();
}
public int getSkillLevel(int sid) {
if (!guildSkills.containsKey(sid)) {
return 0;
}
return guildSkills.get(sid).level;
}
public boolean activateSkill(int skill, String name) {
if (!guildSkills.containsKey(skill)) {
return false;
}
final MapleGuildSkill ourSkill = guildSkills.get(skill);
final MapleStatEffect skillid = SkillFactory.getSkill(skill).getEffect(ourSkill.level);
if (ourSkill.timestamp > System.currentTimeMillis() || skillid.getPeriod() <= 0) {
return false;
}
ourSkill.timestamp = System.currentTimeMillis() + (skillid.getPeriod() * 60000L);
ourSkill.activator = name;
broadcast(GuildPacket.guildSkillPurchased(id, skill, ourSkill.level, ourSkill.timestamp, ourSkill.purchaser, name));
return true;
}
public boolean purchaseSkill(int skill, String name, int cid) {
final MapleStatEffect skillid = SkillFactory.getSkill(skill).getEffect(getSkillLevel(skill) + 1);
if (skillid.getReqGuildLevel() > getLevel() || skillid.getLevel() <= getSkillLevel(skill)) {
return false;
}
MapleGuildSkill ourSkill = guildSkills.get(skill);
if (ourSkill == null) {
ourSkill = new MapleGuildSkill(skill, skillid.getLevel(), 0, name, name);
guildSkills.put(skill, ourSkill);
} else {
ourSkill.level = skillid.getLevel();
ourSkill.purchaser = name;
ourSkill.activator = name;
}
if (skillid.getPeriod() <= 0) {
ourSkill.timestamp = -1L;
} else {
ourSkill.timestamp = System.currentTimeMillis() + (skillid.getPeriod() * 60000L);
}
changed_skills = true;
gainGP(1000, true, cid);
broadcast(GuildPacket.guildSkillPurchased(id, skill, ourSkill.level, ourSkill.timestamp, name, name));
return true;
}
public int getLevel() {
return level;
}
public final int calculateLevel() {
for (int i = 1; i < 10; i++) {
if (gp < GameConstants.getGuildExpNeededForLevel(i)) {
return i;
}
}
return 10;
}
public final void addMemberData(final MaplePacketLittleEndianWriter mplew) {
mplew.write(members.size());
for (final MapleGuildCharacter mgc : members) {
mplew.writeInt(mgc.getId());
}
for (final MapleGuildCharacter mgc : members) {
mplew.writeAsciiString(mgc.getName(), 13);
mplew.writeInt(mgc.getJobId()); //-1 = ??
mplew.writeInt(mgc.getLevel()); //-1 = ??
mplew.writeInt(mgc.getGuildRank());
mplew.writeInt(mgc.isOnline() ? 1 : 0);
mplew.writeInt(mgc.getAllianceRank());
mplew.writeInt(mgc.getGuildContribution());
}
}
// null indicates successful invitation being sent
// keep in mind that this will be called by a handler most of the time
// so this will be running mostly on a channel server, unlike the rest
// of the class
public static final MapleGuildResponse sendInvite(final MapleClient c, final String targetName) {
final MapleCharacter mc = c.getChannelServer().getPlayerStorage().getCharacterByName(targetName);
if (mc == null) {
return MapleGuildResponse.NOT_IN_CHANNEL;
}
if (mc.getGuildId() > 0) {
return MapleGuildResponse.ALREADY_IN_GUILD;
}
mc.getClient().getSession().write(GuildPacket.guildInvite(c.getPlayer().getGuildId(), c.getPlayer().getName(), c.getPlayer().getLevel(), c.getPlayer().getJob()));
return null;
}
public java.util.Collection<MapleGuildCharacter> getMembers() {
return java.util.Collections.unmodifiableCollection(members);
}
public final boolean isInit() {
return init;
}
public final List<MapleBBSThread> getBBS() {
final List<MapleBBSThread> ret = new ArrayList<>(bbs.values());
Collections.sort(ret, new MapleBBSThread.ThreadComparator());
return ret;
}
public final int addBBSThread(final String title, final String text, final int icon, final boolean bNotice, final int posterID) {
final int add = bbs.get(0) == null ? 1 : 0; //add 1 if no notice
changed = true;
final int ret = bNotice ? 0 : Math.max(1, bbs.size() + add);
bbs.put(ret, new MapleBBSThread(ret, title, text, System.currentTimeMillis(), this.id, posterID, icon));
return ret;
}
public final void editBBSThread(final int localthreadid, final String title, final String text, final int icon, final int posterID, final int guildRank) {
final MapleBBSThread thread = bbs.get(localthreadid);
if (thread != null && (thread.ownerID == posterID || guildRank <= 2)) {
changed = true;
bbs.put(localthreadid, new MapleBBSThread(localthreadid, title, text, System.currentTimeMillis(), this.id, thread.ownerID, icon));
}
}
public final void deleteBBSThread(final int localthreadid, final int posterID, final int guildRank) {
final MapleBBSThread thread = bbs.get(localthreadid);
if (thread != null && (thread.ownerID == posterID || guildRank <= 2)) {
changed = true;
bbs.remove(localthreadid);
}
}
public final void addBBSReply(final int localthreadid, final String text, final int posterID) {
final MapleBBSThread thread = bbs.get(localthreadid);
if (thread != null) {
changed = true;
thread.replies.put(thread.replies.size(), new MapleBBSReply(thread.replies.size(), posterID, text, System.currentTimeMillis()));
}
}
public final void deleteBBSReply(final int localthreadid, final int replyid, final int posterID, final int guildRank) {
final MapleBBSThread thread = bbs.get(localthreadid);
if (thread != null) {
final MapleBBSReply reply = thread.replies.get(replyid);
if (reply != null && (reply.ownerID == posterID || guildRank <= 2)) {
changed = true;
thread.replies.remove(replyid);
}
}
}
public boolean hasSkill(int id) {
return guildSkills.containsKey(id);
}
public static void setOfflineGuildStatus(int guildid, byte guildrank, int contribution, byte alliancerank, int cid) {
try {
java.sql.Connection con = DatabaseConnection.getConnection();
try (java.sql.PreparedStatement ps = con.prepareStatement("UPDATE characters SET guildid = ?, guildrank = ?, guildContribution = ?, alliancerank = ? WHERE id = ?")) {
ps.setInt(1, guildid);
ps.setInt(2, guildrank);
ps.setInt(3, contribution);
ps.setInt(4, alliancerank);
ps.setInt(5, cid);
ps.executeUpdate();
}
} catch (SQLException se) {
System.out.println("SQLException: " + se.getLocalizedMessage());
}
}
}