/*
* Gwiazdka oznaczylem uzyte juz komunikaty [Luno]
*1639 The $s1st Olympiad period has started.
*1640 The $s1st Olympiad period has ended.
*1641 The Olympiad game has started.
*1642 The Olympiad game has ended.
1651 The Olympiad game is not currently in progress. <<<po co to ?
*1657 $s1% has gained $s2 Olympiad points.
*1658 $s1% has lost $s2 Olympiad points.
1673 The present record during the current Olympiad session is $s1 wins $s2 defeats. You have earned $s3 Olympiad points.
1674 This command can only be used by a noblesse. <<<< Co to ?
*1480 Do you want to cancel application for joining Olympiad?
*1481 You have been selected No Class Game. Do you want to join?
*1482 You have been selected Classified Game. Do you want to join?
1483 Do you want to become a hero now?
1484 Do you want to use the hero's weapon that you chose?
*1492 $s1 second later, you will move to the Olympiad Stadium.
*1495 $s1 second later, the game starts.
!1496 Starts the game. //Najprawdopodobniej nie uzywany
*1497 $s1% has won the game.
!1498 The game ended in a tie. //chyba nie uzywany
1499 $s1 second later, you will go back to the village.
*1500 You can't join the Olympiad with a sub-job character.
*1501 Only Nobless can participate in the Olympiad.
*1502 You have been already registered in a waiting list of an event. - to jest do olimpiady ??
*1503 You have been registered in a waiting list of Classified Games.
*1504 You have been registered in a waiting list of No Class Games.
1505 You have been deleted from the waiting list of a game.
1506 You have not been registered in a waiting list of a game.
1507 This item can't be equipped for the Olympiad event - nie mozna uzywac hero weapon.
*1508 This item is not available for the Olympiad event. - zrobilem dla potionow, co jeszcze?
*1509 This skill is not available for the Olympiad event -bodajze noblesa skille.
*/
package net.sf.l2j.gameserver;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javolution.util.FastMap;
import net.sf.l2j.L2DatabaseFactory;
import net.sf.l2j.gameserver.model.L2World;
import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
import net.sf.l2j.gameserver.serverpackets.ExOlympiadMode;
import net.sf.l2j.gameserver.serverpackets.SystemMessage;
/**
* Grand Olympiad Engine
*
*
* @author Nemesiss
* @author Luno
*
*
*/
public class GrandOlympiad
{
class PrepareToFight implements Runnable
{
private L2PcInstance _player1;
private L2PcInstance _player2;
private int _stadionid;
public PrepareToFight(L2PcInstance player1, L2PcInstance player2, int stadionid)
{
_player1 = player1;
_player2 = player2;
_stadionid = stadionid;
}
public void run()
{
_player1.SetStadionID(_stadionid);
_player2.SetStadionID(_stadionid);
_player1.SetOlympiadSide(1);
_player2.SetOlympiadSide(2);
_player1.sendPacket(new ExOlympiadMode(ExOlympiadMode.Competitor1));
_player2.sendPacket(new ExOlympiadMode(ExOlympiadMode.Competitor2));
//W momencie pojawienia sie gracza na stadionie odrazu wysle odpowiednie pakiety do wszystkich widzacych go
_player1.teleToLocation( OlympiadArenas.player1X(_stadionid), OlympiadArenas.player1Y(_stadionid), OlympiadArenas.player1Z(_stadionid) );
_player2.teleToLocation( OlympiadArenas.player2X(_stadionid), OlympiadArenas.player2Y(_stadionid), OlympiadArenas.player2Z(_stadionid) );
_stadions[_stadionid] = new OlympiadArenas( _stadionid, _player1, _player2 );
}
}// Koniec klasy PrepareToFight
public class OlympiadStats
{
private int _playerid;
private String _playername;
private int _olympiad_points;
private int _fights;
private int _gametype;
private int _defeats;
private int _victories;
public OlympiadStats( L2PcInstance player )
{
_playerid = player.getObjectId();
_playername = player.getName();
_olympiad_points = 18;
_fights = 0;
_gametype = 0;
_defeats = 0;
_victories = 0;
}
public OlympiadStats( int playerid, String playername, int points, int fights, int gametype, int defeats, int victories )
{
this._playerid = playerid;
this._playername = playername;
this._olympiad_points = points;
this._fights = fights;
this._gametype = gametype;
this._defeats = defeats;
this._victories = victories;
}
public boolean ChangeOlympiadStats( int value )
{
_fights++;
if ( value < 0 )
_defeats++;
else
_victories++;
_olympiad_points += value;
if ( _olympiad_points <= 0 )
{
//Gracz odpada
return true;
}
// Funkcja wywolujaca bedzie usuwac gracza z listy uczestnikow, jesli otrzyma 'true'
return false;
}
public void SetGameType( int gametype ){ _gametype = gametype; }
public int GetPlayerID() { return _playerid; }
public String GetPlayerName() { return _playername; }
public int GetOlympiadPoints() { return _olympiad_points; }
public int GetFightCount() { return _fights; }
public int GetGameType() { return _gametype; }
public int GetDefeats() { return _defeats; }
public int GetVictories() { return _victories; }
} // koniec klasy OlimpiadStats
class sezon_begin implements Runnable
{
public void run()
{
//1639 The $s1st Olympiad period has started.
sendMessageToAll(1639);
SezonStart();
}
} // koniec klasy sezon_begin
class sezon_end implements Runnable
{
public void run()
{
//TODO@ wszystko co sie dzieje na zakonczenie sezonu
// Tu bedzie wysylany msg itd a osobna funkcja bedzie do czysczenia baz itd
// Msg nei powinien byc wysylany po uruchomieniu serwera, jesli przegapilismy koniec sezonu
//1640 The $s1st Olympiad period has ended.
sendMessageToAll(1640);
SezonEnd();
}
} // koniec klasy sezon_end
class start_fights implements Runnable
{
public void run()
{
switch(_during_fights)
{
case 2:
case 3:
case 0://Walki juz zostaly zainicjowane i trwaja
if(_during_fights == 2 )
{
_during_fights = 0;
Announcements.getInstance().announceToAll("Olympiad fights have started"); //custom, ale fajny
}
else if(_during_fights == 3 ) // gdy jest restart w trakcie walk ;)
{
_during_fights = 0;
Announcements.getInstance().announceToAll("Olympiad fights have been resumed"); //custom, ale fajny
}
FindPlayersForFights();
break;
case -1://walki jeszcze sie nie rozpoczely
// odpala walki
//TODO@
//if (aktualna godzina < FIGHTS_START_TIME)
{
ThreadPoolManager.getInstance().scheduleEffect(new start_fights(), ...);
_during_fights = 2;
}
//else <- np gdy byl restart podczas walk
{
if(/* aktualny czas+600000 < czas zwiazany z FIGHTS_STOP_TIME*/)
ThreadPoolManager.getInstance().scheduleEffect(new start_fights(), 600000);// <- dajmy im czas na zalogowanie sie
_during_fights = 3;
}//else: niestety serw sie zresetowal tuz przed koncem i juz nie zdarzymy na zadne walki
ThreadPoolManager.getInstance().scheduleEffect(new stop_fights(), ...);
break;
case 1: //juz po walkach (po co to ? jeszcze nie wiem, albo wiem)
// ustawia _during_fighs na -1, ustawia taska na kolejny start_fights (jutro ;)
_during_fights = -1;
ThreadPoolManager.getInstance().scheduleEffect(new start_fights(), /*jutro*/);
Announcements.getInstance().announceToAll("Olympiad fights have ended"); //custom, ale fajny
//wiecej customu: wypisuje na announce liste 5 osob, ktore dzis zdobyly najwiecej punktow
break;
}
}
} // koniec klasy start_fights
class stop_fights implements Runnable
{
public void run()
{
// ustawia during_fights na 1 (na -1 ustawi to potem start_fights)
_during_fights = 1;
}
}
private static Logger _log = Logger.getLogger(GrandOlympiad.class.getName());
public static final String GRAND_OLYMPIAD_DATA_FILE = "config/olympiad.properties";
public static final String GRAND_OLYMPIAD_HTML_PATH = "data/html/olympiad/";
public static final int SEZON_START_TIME = 10; // moja inicjatywa
public static final int FIGHTS_START_TIME = 16; // wiem ze godziny sie nie zgadzaja, ale po 20 gra malo osob
public static final int FIGHTS_STOP_TIME = 20;
public static final int FIGHTS_INTERVAL = 5; // w minutach
private static GrandOlympiad _instance;
private Map<Integer, OlympiadStats> _OlympiadPlayers;
private Map<Integer, OlympiadStats> _LastOlympiad;
private List<Integer> _LastOlympiadWiners;
private int _sezon;
private int _day;
private int _during_fights; // -1 jeszcze sei nei zaczely, 0 trwaja, 1 juz sie skonczyly, 2,3 - <specjalny stan, szczegoly w start_fights
// ustawic w konstruktorze
private Map<Integer, List> _waitinglist;
int waitingListSizeGeneral; // ile jest ogolnie na waiting liscie
int waitingListSizeNotClass; // ile jest na liscie jako Not class-defined
//Stadiony
OlympiadArenas[] _stadions;
public static GrandOlympiad getInstance()
{
if ( _instance == null )
_instance = new GrandOlympiad();
return _instance;
}
private GrandOlympiad()
{
_OlympiadPlayers = new FastMap<Integer, OlympiadStats>();
_LastOlympiad = new FastMap<Integer, OlympiadStats>();
_waitinglist = new FastMap<Integer, List>();
_during_fights = -1; // przy uruchamianiu serwera nie jestesmy w trakcie walk, bo trzeba je zaczac
// Wczytaj z SQL
LoadOlympiadStatus();
if ( checkOlympiadSezon() == true ) // czyli jestesmy w trakcie sezonu
{
//update daty w statusie
UpdateOlympiadStatus()
// ustawia taska na koniec sezonu
ThreadPoolManager.getInstance().scheduleEffect(new sezon_end(), ....);
// ustawia taska na rozpoczecie rozgrywek w dniu dzisiejszym
ThreadPoolManager.getInstance().scheduleEffect(new start_fights(), /* odrazu */);
}
else
{
//Jak jestesmy tutaj, to znaczy ze przegapilismy koniec sezonu
SezonEnd(); // Czyszczenie tabel itd. rozpoczyna tez nowy sezon
}
LoadOlympiadPlayers(); // wczytuje zarowno aktualnych jak i tych z last olympiad :D
//_stadions = new FastMap<Integer, OlympiadArenas>();
_stadions = new OlympiadArenas[23];
//Ladujemy Stadiony
for ( int i=1; i < 23; i++ )
{
_stadions[i] = null;
}
}
public boolean isRegistered( int playerid )
{
return _OlympiadPlayers.containsKey( playerid );
}
public synchronized boolean RegisterPlayer( L2PcInstance player, boolean classgame )
{
boolean succes = false;
int gametype = 0;
if( classgame ) {
gametype = player.getBaseClass();
}
if ( isRegistered( player.getObjectId() ) )
{
//Gracz juz sie zarejestrowal - dodajemy go do waiting list :)
//Gracz juz jest na waiting list
if (_waitinglist.get(gametype).contains(player.getObjectId()))
succes = false;
else
{
_waitinglist.get(gametype).add(player.getObjectId());
waitingListSizeGeneral++;
if(gametype==0)
waitingListSizeNotClass++;
succes = true;
}
}
else
{
//Gracz napewno nie jest zarejestrowany - mozna go zarejestrowac
OlympiadStats os = new OlympiadStats( player );
os.SetGameType( gametype );
_OlympiadPlayers.put( player.getObjectId(), os );
//Z tego chyba wyskoczy Nullpointer xD
if (_waitinglist.get(gametype) != null)
{
//tymczasowo
_waitinglist.get(gametype).add( player.getObjectId() );
}
else _log.severe("Nullpointer: GrandOlympiad - 224");
waitingListSizeGeneral++;
if(gametype==0)
waitingListSizeNotClass++;
Connection con = null;
PreparedStatement statement = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement("INSERT INTO OlympiadPlayers (sezon, playerid, name, pkt, fights, defeats, victories, gametype) VALUES (?,?,?,?,?,?,?,?)");
statement.setInt(1, _sezon); // sezon
statement.setInt(2, player.getObjectId()); // playerid
statement.setString(3,player.getName()); // name
statement.setInt(4, 18); // pkt
statement.setInt(5, 0); // fights
statement.setInt(6, 0); // defeats
statement.setInt(7, 0); // victories
statement.setInt(8, gametype); // gametype (classid albo 0 jezeli free for all)
statement.execute();
statement.close();
con.close();
}
catch(SQLException e)
{
_log.severe("OlympiadPlayers: Failed to save data: " + e);
}
finally
{
try
{
con.close();
//To nie powinno sie zdarzyc no chyba ze caly SQL lezy
}
catch (Exception e) {}
}
succes = true;
}
return succes;
}
public synchronized boolean UnregisterPlayer (L2PcInstance player)
{
// TODO@ Sa dwa komunikaty, z ktorych wynika ze mozna sie wypisac zarowno z calej olimpiady jak i tylko waiting listy
// jak sie wiec wypisac z tego drugiego ?
return false;
}
//Rejestracja jest tylko jakis czas przed olimpiada czy w trakcie??
//Kiedy dokladnie mozna anulowac??
public boolean CanBeHero( int playerid )
{
return _LastOlympiadWiners.contains( playerid ); // To tylko po to, zeby moc sobie wlaczyc hero i wziac bron od statuly ? //tak
}
public int GetPlayerPts( int playerid )
{
return _OlympiadPlayers.get( playerid ).GetOlympiadPoints();
}
public int GetPlayerFights( int playerid )
{
return _OlympiadPlayers.get( playerid ).GetFightCount();
}
public int getWaitingListSizeGeneral()
{
return this.waitingListSizeGeneral;
}
public int getWaitingListSizeNotClass()
{
return this.waitingListSizeNotClass;
}
public void ChangeOlympiadStats(int playerid, int value )
{
_OlympiadPlayers.get( playerid ).ChangeOlympiadStats( value );
}
private void LoadOlympiadStatus()
{
// tabela: olympiad_status (sezon, day) <- poki co tyle.
// insert into olympiad_status values (0,100); na poczatku ustawi poprawny
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT sezon, day FROM olympiad_status");
ResultSet rset = statement.executeQuery();
rset.next();
_sezon = rset.getInt( "sezon" );
_day = rset.getInt( "day" );
rset.close();
statement.close();
}
catch(SQLException e)
{
_log.warning("could not load olympiad status :"+e.getMessage());
}
finally
{
try { con.close(); }catch(Exception e){}
}
}
private void UpdateOlympiadStatus()
{
Connection con = null;
PreparedStatement statement = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement("UPDATE olympiad_status set sezon=?, day =?");
statement.setInt(1, _sezon);
statement.setInt(2, _day);
statement.execute();
statement.close();
con.close();
}
catch(SQLException e)
{
_log.severe("olympiad_status: Failed to save data: " + e);
}
finally
{
try
{
con.close();
//To nie powinno sie zdarzyc no chyba ze caly SQL lezy
}
catch (Exception e) {}
}
}
private void LoadOlympiadPlayers()
{
// Budowa tabeli: sezon,playerid,name,pkt,fights,defeats,victories,gametype
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT sezon,playerid,name,pts,fights,defeats,victories,gametype,sezon FROM OlympiadPlayers");
ResultSet rset = statement.executeQuery();
while( rset.next() )
{
OlympiadStats os = new OlympiadStats( rset.getInt( "playerid" ),
rset.getString( "name" ),
rset.getInt( "pts" ),
rset.getInt("fights"),
rset.getInt("gametype"),
rset.getInt("defeats"),
rset.getInt("victories") );
if(rset.getInt("sezon") == _sezon )
_OlympiadPlayers.put( rset.getInt( "playerid" ), os );
else
_LastOlympiad.put( rset.getInt( "playerid" ), os );
}
rset.close();
statement.close();
}
catch (SQLException e)
{
_log.warning("could not load from OlympiadPlayers :"+e.getMessage());
}
finally
{
try { con.close(); } catch (Exception e) {}
}
}
private void SezonStart()
{ /* Funkcja jest wywolana gdy normalnie sezon sie zaczyna, a takze gdy przegapilismy rozpoczecie*/
_sezon++;
_day = /*aktualny dzien */;
//update mysql
UpdateOlympiadStatus();
ThreadPoolManager.getInstance().scheduleEffect(new start_fights(), ...);
ThreadPoolManager.getInstance().scheduleEffect(new sezon_end(), ...)//chociaz serwer chyba nie da rady miesiac bez restartu, ale moze....
}
private void SezonEnd()
{
//Mam na mysli to co dzieje sie na zakonczenie miesiaca
//TODO@ przeczyscic SQL
//aktualne dane graczy ustawic jako LastOlympiad
//Dodac zwyciezcow na WinerList
//Zapisac zmiany w SQL
//Byli hero juz nie sa Hero - trzeba pozabierac statusy
HeroTable.getInstance().cleartable(); //(smutne :D )
for (int id: _LastOlympiadWiners)
{
//TODO@ skrypt zabierajacy status hero z SQL (characters)
//where character_id = id set ishero = 0 :)
}
/* jesli serwer wysypal sie przed zakonczeniem sezonu a wstal po rozpoczeciu nowego: */
if(checkOlympiadSezon() == false ) // w ogole, jesli przegapilismy
{
if(/* aktualna godzina (dzien itd)> data zwiazana z poczatkiem sezonu*/)
{
SezonStart();
}
else // wysypal sie przed zakonczeniem sezonu, ale uruchomil przed rozpoczeciem nowego
{
ThreadPoolManager.getInstance().scheduleEffect(new sezon_begin(), ...);// po co duplikat ?
}
}
ThreadPoolManager.getInstance().scheduleEffect(new sezon_begin(), ...);
}
private void FindPlayersForFights()
{
//TODO@ Posortuj i wybierz graczy do walki w odpowiednich
//przedzialach klass i na odpowiednich stadionach
L2PcInstance p1 = null;
L2PcInstance p2 = null;
Prepare(p1,p2,1);
if(/* aktualna godzina + FIGHTS_INTERVAL*2(lub 3) < czas zwiazany z FIGHTS_STOP_TIME */)
{
ThreadPoolManager.getInstance().scheduleEffect(new start_fights(), FIGHTS_INTERVAL);
/* po to , zeby okres walk sie nie konczyl gdy jakas walka jest w trakcie */
}
}
public void Prepare(L2PcInstance player1, L2PcInstance player2, int stadionid)
{
//1492 $s1 second later, you will move to the Olympiad Stadium.
SystemMessage sm = new SystemMessage(1492);
sm.addNumber(30);
player1.sendPacket(sm);
player2.sendPacket(sm);
//po 30s teleportuj na stadion (moze zrobimy taki myk, ze gracz musi zatwierdzic to (glupio sciagac kogos AFK) - ciezko bedzie to zrobic :)
ThreadPoolManager.getInstance().scheduleEffect(new PrepareToFight(player1, player2, stadionid), 30000);
}
public OlympiadArenas GetStadion(int id) { return _stadions[id]; }
public void ClearStadion(int id) {
_stadions[id] = null;
}
private boolean checkOlympiadSezon()
{
/* if dzisiejszy dzien >= day return true
* else:
*/ return false
}
public void sendMessageToAll(int sysMsgId)
{
SystemMessage sm = new SystemMessage(sysMsgId);
for (L2PcInstance player : L2World.getInstance().getAllPlayers())
player.sendPacket(sm);
}
// TODO@ 3 punkty dodawane co tydzien
/* At the beginning of each Olympiad period, 18 points are equally awarded to all Noblesse,
and 3 points each week thereafter. */
/* Participating in a competition is possible only through the Olympiad Master, and the hours
of competition are 8:00 PM CST to 12:00 AM CST (8:00 PM GMT+1 to 12:00 AM GMT+1 on the Teon server).
No competition requests are taken outside of competition hours.
Competitors will be matched randomly and summoned to the coliseum for competition. - jednak losowo
During the competition, a character whose HP has reached 0 will merely lose the competition, but not die. - nie ginie
*/
}