/*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package lineage2.gameserver.model.entity;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import lineage2.commons.dbutils.DbUtils;
import lineage2.gameserver.Config;
import lineage2.gameserver.data.StringHolder;
import lineage2.gameserver.database.DatabaseFactory;
import lineage2.gameserver.database.mysql;
import lineage2.gameserver.model.Player;
import lineage2.gameserver.model.Skill;
import lineage2.gameserver.model.World;
import lineage2.gameserver.model.entity.olympiad.Olympiad;
import lineage2.gameserver.model.items.ItemInstance;
import lineage2.gameserver.model.items.PcInventory;
import lineage2.gameserver.model.pledge.Alliance;
import lineage2.gameserver.model.pledge.Clan;
import lineage2.gameserver.network.serverpackets.NpcHtmlMessage;
import lineage2.gameserver.network.serverpackets.SocialAction;
import lineage2.gameserver.network.serverpackets.SystemMessage;
import lineage2.gameserver.tables.ClanTable;
import lineage2.gameserver.tables.SkillTable;
import lineage2.gameserver.templates.StatsSet;
import lineage2.gameserver.utils.HtmlUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Mobius
* @version $Revision: 1.0 $
*/
public class Hero
{
/**
* Field _log.
*/
private static final Logger _log = LoggerFactory.getLogger(Hero.class);
/**
* Field _instance.
*/
private static Hero _instance;
/**
* Field GET_HEROES. (value is ""SELECT * FROM heroes WHERE played = 1"")
*/
private static final String GET_HEROES = "SELECT * FROM heroes WHERE played = 1";
/**
* Field GET_ALL_HEROES. (value is ""SELECT * FROM heroes"")
*/
private static final String GET_ALL_HEROES = "SELECT * FROM heroes";
/**
* Field _heroes.
*/
private static Map<Integer, StatsSet> _heroes;
/**
* Field _completeHeroes.
*/
private static Map<Integer, StatsSet> _completeHeroes;
/**
* Field _herodiary.
*/
private static Map<Integer, List<HeroDiary>> _herodiary;
/**
* Field _heroMessage.
*/
private static Map<Integer, String> _heroMessage;
/**
* Field COUNT. (value is ""count"")
*/
public static final String COUNT = "count";
/**
* Field PLAYED. (value is ""played"")
*/
public static final String PLAYED = "played";
/**
* Field CLAN_NAME. (value is ""clan_name"")
*/
public static final String CLAN_NAME = "clan_name";
/**
* Field CLAN_CREST. (value is ""clan_crest"")
*/
public static final String CLAN_CREST = "clan_crest";
/**
* Field ALLY_NAME. (value is ""ally_name"")
*/
public static final String ALLY_NAME = "ally_name";
/**
* Field ALLY_CREST. (value is ""ally_crest"")
*/
public static final String ALLY_CREST = "ally_crest";
/**
* Field ACTIVE. (value is ""active"")
*/
public static final String ACTIVE = "active";
/**
* Field MESSAGE. (value is ""message"")
*/
public static final String MESSAGE = "message";
/**
* Method getInstance.
* @return Hero
*/
public static Hero getInstance()
{
if (_instance == null)
{
_instance = new Hero();
}
return _instance;
}
/**
* Constructor for Hero.
*/
public Hero()
{
init();
}
/**
* Method HeroSetClanAndAlly.
* @param charId int
* @param hero StatsSet
*/
private static void HeroSetClanAndAlly(int charId, StatsSet hero)
{
Entry<Clan, Alliance> e = ClanTable.getInstance().getClanAndAllianceByCharId(charId);
hero.set(CLAN_CREST, e.getKey() == null ? 0 : e.getKey().getCrestId());
hero.set(CLAN_NAME, e.getKey() == null ? "" : e.getKey().getName());
hero.set(ALLY_CREST, e.getValue() == null ? 0 : e.getValue().getAllyCrestId());
hero.set(ALLY_NAME, e.getValue() == null ? "" : e.getValue().getAllyName());
e = null;
}
/**
* Method init.
*/
private void init()
{
_heroes = new ConcurrentHashMap<>();
_completeHeroes = new ConcurrentHashMap<>();
_herodiary = new ConcurrentHashMap<>();
_heroMessage = new ConcurrentHashMap<>();
Connection con = null;
PreparedStatement statement = null;
ResultSet rset = null;
try
{
con = DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement(GET_HEROES);
rset = statement.executeQuery();
while (rset.next())
{
StatsSet hero = new StatsSet();
int charId = rset.getInt(Olympiad.CHAR_ID);
hero.set(Olympiad.CHAR_NAME, Olympiad.getNobleName(charId));
hero.set(Olympiad.CLASS_ID, Olympiad.getNobleClass(charId));
hero.set(COUNT, rset.getInt(COUNT));
hero.set(PLAYED, rset.getInt(PLAYED));
hero.set(ACTIVE, rset.getInt(ACTIVE));
HeroSetClanAndAlly(charId, hero);
loadDiary(charId);
loadMessage(charId);
_heroes.put(charId, hero);
}
DbUtils.close(statement, rset);
statement = con.prepareStatement(GET_ALL_HEROES);
rset = statement.executeQuery();
while (rset.next())
{
StatsSet hero = new StatsSet();
int charId = rset.getInt(Olympiad.CHAR_ID);
hero.set(Olympiad.CHAR_NAME, Olympiad.getNobleName(charId));
hero.set(Olympiad.CLASS_ID, Olympiad.getNobleClass(charId));
hero.set(COUNT, rset.getInt(COUNT));
hero.set(PLAYED, rset.getInt(PLAYED));
hero.set(ACTIVE, rset.getInt(ACTIVE));
HeroSetClanAndAlly(charId, hero);
_completeHeroes.put(charId, hero);
}
}
catch (SQLException e)
{
_log.warn("Hero System: Couldnt load Heroes", e);
}
finally
{
DbUtils.closeQuietly(con, statement, rset);
}
_log.info("Hero System: Loaded " + _heroes.size() + " Heroes.");
_log.info("Hero System: Loaded " + _completeHeroes.size() + " all time Heroes.");
}
/**
* Method getHeroes.
* @return Map<Integer,StatsSet>
*/
public Map<Integer, StatsSet> getHeroes()
{
return _heroes;
}
/**
* Method clearHeroes.
*/
public synchronized void clearHeroes()
{
mysql.set("UPDATE heroes SET played = 0, active = 0");
if (!_heroes.isEmpty())
{
for (StatsSet hero : _heroes.values())
{
if (hero.getInteger(ACTIVE) == 0)
{
continue;
}
String name = hero.getString(Olympiad.CHAR_NAME);
Player player = World.getPlayer(name);
if (player != null)
{
PcInventory inventory = player.getInventory();
inventory.writeLock();
try
{
for (ItemInstance item : player.getInventory().getItems())
{
if (item.isHeroWeapon())
{
player.getInventory().destroyItem(item);
}
}
}
finally
{
inventory.writeUnlock();
}
player.setHero(false);
player.updatePledgeClass();
player.broadcastUserInfo();
}
}
}
_heroes.clear();
_herodiary.clear();
}
/**
* Method computeNewHeroes.
* @param newHeroes List<StatsSet>
* @return boolean
*/
public synchronized boolean computeNewHeroes(List<StatsSet> newHeroes)
{
if (newHeroes.size() == 0)
{
return true;
}
Map<Integer, StatsSet> heroes = new ConcurrentHashMap<>();
boolean error = false;
for (StatsSet hero : newHeroes)
{
int charId = hero.getInteger(Olympiad.CHAR_ID);
if ((_completeHeroes != null) && _completeHeroes.containsKey(charId))
{
StatsSet oldHero = _completeHeroes.get(charId);
int count = oldHero.getInteger(COUNT);
oldHero.set(COUNT, count + 1);
oldHero.set(PLAYED, 1);
oldHero.set(ACTIVE, 0);
heroes.put(charId, oldHero);
}
else
{
StatsSet newHero = new StatsSet();
newHero.set(Olympiad.CHAR_NAME, hero.getString(Olympiad.CHAR_NAME));
newHero.set(Olympiad.CLASS_ID, hero.getInteger(Olympiad.CLASS_ID));
newHero.set(COUNT, 1);
newHero.set(PLAYED, 1);
newHero.set(ACTIVE, 0);
heroes.put(charId, newHero);
}
addHeroDiary(charId, HeroDiary.ACTION_HERO_GAINED, 0);
loadDiary(charId);
}
_heroes.putAll(heroes);
heroes.clear();
updateHeroes(0);
return error;
}
/**
* Method updateHeroes.
* @param id int
*/
public void updateHeroes(int id)
{
Connection con = null;
PreparedStatement statement = null;
try
{
con = DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement("REPLACE INTO heroes (char_id, count, played, active) VALUES (?,?,?,?)");
for (Integer heroId : _heroes.keySet())
{
if ((id > 0) && (heroId != id))
{
continue;
}
StatsSet hero = _heroes.get(heroId);
statement.setInt(1, heroId);
statement.setInt(2, hero.getInteger(COUNT));
statement.setInt(3, hero.getInteger(PLAYED));
statement.setInt(4, hero.getInteger(ACTIVE));
statement.execute();
if ((_completeHeroes != null) && !_completeHeroes.containsKey(heroId))
{
HeroSetClanAndAlly(heroId, hero);
_completeHeroes.put(heroId, hero);
}
}
}
catch (SQLException e)
{
_log.warn("Hero System: Couldnt update Heroes");
_log.error("", e);
}
finally
{
DbUtils.closeQuietly(con, statement);
}
}
/**
* Method isHero.
* @param id int
* @return boolean
*/
public boolean isHero(int id)
{
if ((_heroes == null) || _heroes.isEmpty())
{
return false;
}
if (_heroes.containsKey(id) && (_heroes.get(id).getInteger(ACTIVE) == 1))
{
return true;
}
return false;
}
/**
* Method isInactiveHero.
* @param id int
* @return boolean
*/
public boolean isInactiveHero(int id)
{
if ((_heroes == null) || _heroes.isEmpty())
{
return false;
}
if (_heroes.containsKey(id) && (_heroes.get(id).getInteger(ACTIVE) == 0))
{
return true;
}
return false;
}
/**
* Method activateHero.
* @param player Player
*/
public void activateHero(Player player)
{
StatsSet hero = _heroes.get(player.getObjectId());
hero.set(ACTIVE, 1);
_heroes.remove(player.getObjectId());
_heroes.put(player.getObjectId(), hero);
if (player.getBaseClassId() == player.getActiveClassId())
{
addSkills(player);
}
player.setHero(true);
player.updatePledgeClass();
player.broadcastPacket(new SocialAction(player.getObjectId(), SocialAction.GIVE_HERO));
if ((player.getClan() != null) && (player.getClan().getLevel() >= 5))
{
player.getClan().incReputation(5000, true, "Hero:activateHero:" + player);
player.getClan().broadcastToOtherOnlineMembers(new SystemMessage(SystemMessage.CLAN_MEMBER_S1_WAS_NAMED_A_HERO_2S_POINTS_HAVE_BEEN_ADDED_TO_YOUR_CLAN_REPUTATION_SCORE).addString(player.getName()).addNumber(Math.round(5000 * Config.RATE_CLAN_REP_SCORE)), player);
}
player.broadcastUserInfo();
updateHeroes(player.getObjectId());
}
/**
* Method addSkills.
* @param player Player
*/
public static void addSkills(Player player)
{
player.addSkill(SkillTable.getInstance().getInfo(Skill.SKILL_HEROIC_MIRACLE, 1));
player.addSkill(SkillTable.getInstance().getInfo(Skill.SKILL_HEROIC_BERSERKER, 1));
player.addSkill(SkillTable.getInstance().getInfo(Skill.SKILL_HEROIC_VALOR, 1));
player.addSkill(SkillTable.getInstance().getInfo(Skill.SKILL_HEROIC_GRANDEUR, 1));
player.addSkill(SkillTable.getInstance().getInfo(Skill.SKILL_HEROIC_DREAD, 1));
}
/**
* Method removeSkills.
* @param player Player
*/
public static void removeSkills(Player player)
{
player.removeSkillById(Skill.SKILL_HEROIC_MIRACLE);
player.removeSkillById(Skill.SKILL_HEROIC_BERSERKER);
player.removeSkillById(Skill.SKILL_HEROIC_VALOR);
player.removeSkillById(Skill.SKILL_HEROIC_GRANDEUR);
player.removeSkillById(Skill.SKILL_HEROIC_DREAD);
}
/**
* Method loadDiary.
* @param charId int
*/
public void loadDiary(int charId)
{
List<HeroDiary> diary = new ArrayList<>();
Connection con = null;
PreparedStatement statement = null;
ResultSet rset = null;
try
{
con = DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement("SELECT * FROM heroes_diary WHERE charId=? ORDER BY time ASC");
statement.setInt(1, charId);
rset = statement.executeQuery();
while (rset.next())
{
long time = rset.getLong("time");
int action = rset.getInt("action");
int param = rset.getInt("param");
HeroDiary d = new HeroDiary(action, time, param);
diary.add(d);
}
_herodiary.put(charId, diary);
if (Config.DEBUG)
{
_log.info("Hero System: Loaded " + diary.size() + " diary entries for Hero(object id: #" + charId + ")");
}
}
catch (SQLException e)
{
_log.warn("Hero System: Couldnt load Hero Diary for CharId: " + charId, e);
}
finally
{
DbUtils.closeQuietly(con, statement, rset);
}
}
/**
* Method showHeroDiary.
* @param activeChar Player
* @param heroclass int
* @param charid int
* @param page int
*/
public void showHeroDiary(Player activeChar, int heroclass, int charid, int page)
{
final int perpage = 10;
List<HeroDiary> mainlist = _herodiary.get(charid);
if (mainlist != null)
{
NpcHtmlMessage html = new NpcHtmlMessage(activeChar, null);
html.setFile("olympiad/monument_hero_info.htm");
html.replace("%title%", StringHolder.getInstance().getNotNull(activeChar, "hero.diary"));
html.replace("%heroname%", Olympiad.getNobleName(charid));
html.replace("%message%", _heroMessage.get(charid));
List<HeroDiary> list = new ArrayList<>(mainlist);
Collections.reverse(list);
boolean color = true;
final StringBuilder fList = new StringBuilder(500);
int counter = 0;
int breakat = 0;
for (int i = (page - 1) * perpage; i < list.size(); i++)
{
breakat = i;
HeroDiary diary = list.get(i);
Map.Entry<String, String> entry = diary.toString(activeChar);
fList.append("<tr><td>");
if (color)
{
fList.append("<table width=270 bgcolor=\"131210\">");
}
else
{
fList.append("<table width=270>");
}
fList.append("<tr><td width=270><font color=\"LEVEL\">" + entry.getKey() + "</font></td></tr>");
fList.append("<tr><td width=270>" + entry.getValue() + "</td></tr>");
fList.append("<tr><td> </td></tr></table>");
fList.append("</td></tr>");
color = !color;
counter++;
if (counter >= perpage)
{
break;
}
}
if (breakat < (list.size() - 1))
{
html.replace("%buttprev%", HtmlUtils.PREV_BUTTON);
html.replace("%prev_bypass%", "_diary?class=" + heroclass + "&page=" + (page + 1));
}
else
{
html.replace("%buttprev%", StringUtils.EMPTY);
}
if (page > 1)
{
html.replace("%buttnext%", HtmlUtils.NEXT_BUTTON);
html.replace("%next_bypass%", "_diary?class=" + heroclass + "&page=" + (page - 1));
}
else
{
html.replace("%buttnext%", StringUtils.EMPTY);
}
html.replace("%list%", fList.toString());
activeChar.sendPacket(html);
}
}
/**
* Method addHeroDiary.
* @param playerId int
* @param id int
* @param param int
*/
public void addHeroDiary(int playerId, int id, int param)
{
insertHeroDiary(playerId, id, param);
List<HeroDiary> list = _herodiary.get(playerId);
if (list != null)
{
list.add(new HeroDiary(id, System.currentTimeMillis(), param));
}
}
/**
* Method insertHeroDiary.
* @param charId int
* @param action int
* @param param int
*/
private void insertHeroDiary(int charId, int action, int param)
{
Connection con = null;
PreparedStatement statement = null;
try
{
con = DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement("INSERT INTO heroes_diary (charId, time, action, param) values(?,?,?,?)");
statement.setInt(1, charId);
statement.setLong(2, System.currentTimeMillis());
statement.setInt(3, action);
statement.setInt(4, param);
statement.execute();
statement.close();
}
catch (SQLException e)
{
_log.error("SQL exception while saving DiaryData.", e);
}
finally
{
DbUtils.closeQuietly(con, statement);
}
}
/**
* Method loadMessage.
* @param charId int
*/
public void loadMessage(int charId)
{
Connection con = null;
PreparedStatement statement = null;
ResultSet rset = null;
try
{
String message = null;
con = DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement("SELECT message FROM heroes WHERE char_id=?");
statement.setInt(1, charId);
rset = statement.executeQuery();
rset.next();
message = rset.getString("message");
_heroMessage.put(charId, message);
}
catch (SQLException e)
{
_log.error("Hero System: Couldnt load Hero Message for CharId: " + charId, e);
}
finally
{
DbUtils.closeQuietly(con, statement, rset);
}
}
/**
* Method setHeroMessage.
* @param charId int
* @param message String
*/
public void setHeroMessage(int charId, String message)
{
_heroMessage.put(charId, message);
}
/**
* Method saveHeroMessage.
* @param charId int
*/
public void saveHeroMessage(int charId)
{
if (_heroMessage.get(charId) == null)
{
return;
}
Connection con = null;
PreparedStatement statement = null;
try
{
con = DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement("UPDATE heroes SET message=? WHERE char_id=?;");
statement.setString(1, _heroMessage.get(charId));
statement.setInt(2, charId);
statement.execute();
statement.close();
}
catch (SQLException e)
{
_log.error("SQL exception while saving HeroMessage.", e);
}
finally
{
DbUtils.closeQuietly(con, statement);
}
}
/**
* Method shutdown.
*/
public void shutdown()
{
for (int charId : _heroMessage.keySet())
{
saveHeroMessage(charId);
}
}
/**
* Method getHeroByClass.
* @param classid int
* @return int
*/
public int getHeroByClass(int classid)
{
if (!_heroes.isEmpty())
{
for (Integer heroId : _heroes.keySet())
{
StatsSet hero = _heroes.get(heroId);
if (hero.getInteger(Olympiad.CLASS_ID) == classid)
{
return heroId;
}
}
}
return 0;
}
/**
* Method getHeroStats.
* @param classId int
* @return Map.Entry<Integer,StatsSet>
*/
public Map.Entry<Integer, StatsSet> getHeroStats(int classId)
{
if (!_heroes.isEmpty())
{
for (Map.Entry<Integer, StatsSet> entry : _heroes.entrySet())
{
if (entry.getValue().getInteger(Olympiad.CLASS_ID) == classId)
{
return entry;
}
}
}
return null;
}
/**
* Method deleteHero.
* @param player Player
*/
public static void deleteHero(Player player)
{
Connection con = null;
PreparedStatement statement = null;
try
{
con = DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement("REPLACE INTO heroes (char_id, count, played, active) VALUES (?,?,?,?)");
for (Integer heroId : _heroes.keySet())
{
int id = player.getObjectId();
if ((id > 0) && (heroId != id))
{
continue;
}
StatsSet hero = _heroes.get(heroId);
statement.setInt(1, heroId);
statement.setInt(2, hero.getInteger(COUNT));
statement.setInt(3, hero.getInteger(PLAYED));
statement.setInt(4, 0);
statement.execute();
if ((_completeHeroes != null) && !_completeHeroes.containsKey(heroId))
{
_completeHeroes.remove(heroId);
}
}
}
catch (SQLException e)
{
_log.warn("Hero System: Couldnt update Heroes");
_log.error("", e);
}
finally
{
DbUtils.closeQuietly(con, statement);
}
}
}