[SEGNALAZIONE BUG][GENERIC] SERVER FREYA

  
Discussioni sul Server Lineage II Nostalgia
http://www.lineage2.gigarent.it

Moderatore: andreagighi

[SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda andreagighi » martedì 16 febbraio 2010, 13:36

Sezione per segnalare tutti i bug che non riguardano skill e geodata...
Segnalare solo BUG con prove certe da official... non voglio bug di cui non siete sicuri.

P.S. SEGNALARE UN BUG A POST !!!

17/12/2010
* Ogni post cancellato si presume fixato o non corretto.
* Tutti i fix li trovate nella lista aggiornamenti sul sito... o sul launcher.
* Verranno messe negli aggiornamenti da oggi anche le singole skill dei pg se modificate.

18/01/2011
* Da oggi potete postare i bug presenti sul live server in quanto migrato di piattaforma.
Avatar utente
andreagighi
Amministratore
 
Messaggi: 2042
Iscritto il: sabato 26 giugno 2004, 16:55
Località: Genova, Italy

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda DarkRevenant » mercoledì 23 febbraio 2011, 8:38

Anche se un Bug minore, dopo averlo fatto un paio di volte negli ultimi giorni segnalo che il Kamaloka 46 droppa regolarmente ma non da EXP, non so quali altri abbiano questo problema ma se li trovo sarà mia premura segnalarlo,

Buon Lavoro.
Avatar utente
DarkRevenant
Niubbo
 
Messaggi: 20
Iscritto il: giovedì 22 aprile 2010, 22:37

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda Varg » mercoledì 23 febbraio 2011, 17:53

Bug del Warlock (e forse anche degli altri summoner)

Posto in Generic perchè non si riferisce unicamente ad una skill ma a vari eventi che accadono a summon evocata all'interno del Rim Kamaloka (Kamaloka singolo).

La summon quando viene mandata ad attaccare il mob corre fino al mob per poi "teletrasportarsi" di nuovo accanto al summoner o a metà strada, riesce a colpire il mob solo se "accompagnata". Ogni "teletrasporto" è in qualche modo legato alla raccolta delle erbe e ad altre azioni compiute dal summoner.

Data la strana natura del bug e la difficoltà nello spiegarlo, ho frapsato il tutto ed ecco il video visionabile anche in HD:

http://www.youtube.com/watch?v=M7HQk5zTNbw


Non si tratta di lag personale inquanto lo stesso bug si verifica da quando è stato implementato il kamaloka singolo, avevo anche postato già il bug in passato.

Spero non sia di difficile risoluzione, grazie mille in anticipo.
Immagine
Avatar utente
Varg
Parla spesso
 
Messaggi: 584
Iscritto il: giovedì 8 febbraio 2007, 17:14
Località: Messina

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda Varg » sabato 19 marzo 2011, 21:14

Non so se sono già di vostra conoscenza questi bug riguardanti il Kratei's Cube:

1) Quando si muore e si rientra non si viene ribuffati.
2) Il Kratei's Watcher dovrebbe buffare/debuffare a seconda del colore e cambiare colore quando attaccato (invece adesso "muore").
3) Mancano le opzioni per i livelli 70 - 75 e 76 - 79.

fonte: http://www.l2gc.com/fantasyisland/krateis_cube.html
Immagine
Avatar utente
Varg
Parla spesso
 
Messaggi: 584
Iscritto il: giovedì 8 febbraio 2007, 17:14
Località: Messina

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda gryphon » sabato 2 aprile 2011, 7:27

Bug: Rudolph necklace
Descrizione: non viene evocata la renna, nè risulta possibile depositarlo in wh.
Avatar utente
gryphon
Figlio del forum
 
Messaggi: 1934
Iscritto il: giovedì 25 gennaio 2007, 18:15
Località: Quel Paese (mi ci mandavano tutti)

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda **Illyria** » mercoledì 6 aprile 2011, 12:02

Quando si apre il seed of destruction e ci sono le fontanelle, le porte sono tutte buggate. Sono tutte aperte ma per passare devi attraversarle in un punto preciso.
Inoltre, al restart notturno, si chiudono tutte, per cui chi è già all'interno può continuare a farmare stando però fisso in una stanza, mentre chi sta fuori non ha alcuna possibilità di entrare.
Avatar utente
**Illyria**
Vive nel forum
 
Messaggi: 1226
Iscritto il: venerdì 18 febbraio 2011, 14:19

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda Jumbo » lunedì 11 aprile 2011, 15:05

GM UPDATE !
retested :

1. Def attributes no longer transfer to pet( it's taking double dmg's compared to 3 weeks ago).
1. Confirmed it works, base element def of summon is 100 for each element... and it transfer 100% of element of his master (tested).

2. atk attributes no longer transfer to pet.
2. Confirmed, it works, base element correctly transfered (tested.


TODO:
3. summon's are unbuffed when u summon them, while they should have theyr master's buff's.
3. Confirmed - not working : the summon is summoned UNBUFFED. The summon has to get the same buffs of the masters when it gets summoned.

4. summon's have a max 20 buff's cap, whyle they should have theyr master's buff' cap( curently they get over buffed all the time).
4. confirmed - summon capping at 20 buff slots. The summon has to have the same buffslots of the master.

5. summon's dont get certain buff's from theyr master( buff's like celestial( trigger)/ hero ud and berserk, also if u buff urself with pet buff's the pet dont get the buff's also u need to buff twice ).
5. confirmed - not working.

6. from time to time summ0on's are getting stucked, u need to press follow every time for it to follow.
6. solved

7. summon's skill's window is not working properly, for example in order for the servitor to stop attacking u need to pres "Stop" action liek 10 times.
7. confirmed. You have to spam "stop" to let the summon stop attacking.

9. cubics no longer work, smart cubic hardly removing any debuff, other cubics hardly activates( for example spark cubic .. activates once at 20 min's and failling)
9 - confirmed - all cubics being defective (SK - TK - Summoners), especially SMART CUBIC. They barely trigger, while on retail they trigger every 7-9 seconds.

12. Curse of shade/Mass curse of shade has no aggro effect( only lands curse, doesnt change target on summon nore lock it).
12 - Confirmed. Aggression effect not landing on players.

- lvl 83 transform should be available in oly like in this video(min 3:55a and 5:25)
- Confirmed. it MUST be available in olympiad (spirit of the cat should be?)

GEO ISSUE:
8. summon's are dropping in textures and when they come back up they have 0 HP( 1 hit and they die, u can also lose it under textures being unable to unsummon it or summon other summon).
8. can't check this, probably bad geodata.
Ultima modifica di Jumbo il mercoledì 11 maggio 2011, 10:20, modificato 2 volte in totale.
Jumbo
Si interessa
 
Messaggi: 60
Iscritto il: sabato 9 aprile 2011, 14:30

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda gryphon » martedì 19 aprile 2011, 15:13

Bug: fortress of the dead
Descrizione: a parte l'orario ballerino, non fa più partire l'assedio (aggiorna la data, toglie l'iscrizione ma l'assedio non parte)
Avatar utente
gryphon
Figlio del forum
 
Messaggi: 1934
Iscritto il: giovedì 25 gennaio 2007, 18:15
Località: Quel Paese (mi ci mandavano tutti)

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda Jumbo » lunedì 25 aprile 2011, 17:10

According to http://www.lineage2.com/Knowledge/clans.html all heroes obtain the rank of Marquis in clan. However currently the hero status has no effect on rank.
Jumbo
Si interessa
 
Messaggi: 60
Iscritto il: sabato 9 aprile 2011, 14:30

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda Extender » martedì 26 aprile 2011, 12:19

dopo aver fatto il clan lvl 11 abbiamo provato a prendere le nuove skill ma l'npc dice di averle gia' imparate tutte(cosa ovviamente falsa visto che abbiamo fatto il clan il minuto prima).
il problema non sta nei crp o negli oath visto che abbiamo anche quelli.
screen:
lvl clan e skill al momento: http://img217.imageshack.us/i/shot00032pj.jpg/
skill su pg marquis(tutte quelle disponibili: http://img705.imageshack.us/i/shot00031f.jpg/
clan leader con l'npc che da le skill: http://img864.imageshack.us/f/asdwikeqo.jpg/
risposta dell'npc: http://img200.imageshack.us/i/asd2az.jpg/
spero la cosa possa essere risolta al più presto visto che le skill in questione sono molto importanti.


Extender
Extender
Niubbo
 
Messaggi: 6
Iscritto il: mercoledì 22 dicembre 2010, 15:53

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda **Illyria** » mercoledì 27 aprile 2011, 12:47

caratopulos ha scritto:Quando il Seed of Destruction è aperto non funziona l'Aerial Cleft Battleground

Inoltre quando si apre il seed of destruction le porte sono strane. Prima del restart notturno sono aperte, ma difficili da attraversare, come se una barriera invisibile fosse ancora presente.
Al restart le porte sono proprio chiuse, quindi chi sta dentro resta tranquillo, chi sta fuori resta fuori.
Inoltre, continua a restare tipo instancezone, quindi se crashi o restarti ti trovi fuori, mentre dovrebbe essere aperto e dovresti poter restartare a piacimento.
Avatar utente
**Illyria**
Vive nel forum
 
Messaggi: 1226
Iscritto il: venerdì 18 febbraio 2011, 14:19

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda **Illyria** » martedì 3 maggio 2011, 0:03

Se si gkappa mentre un nemico blessa o slogga ecc, resta la sua immagine residua. Oggi mi è successo con hide. Ciò mi ha permesso di inseguire logum, e ciucciargli i buff mentre era in hide (per tutti tranne per me a quanto pare asd)
Avatar utente
**Illyria**
Vive nel forum
 
Messaggi: 1226
Iscritto il: venerdì 18 febbraio 2011, 14:19

Re: [SEGNALAZIONE BUG][GENERIC] SERVER FREYA

Messaggioda NewMoon » mercoledì 4 maggio 2011, 14:49

Nessuna trappola dei trickster funziona ne sui pg ne sui mob anche se +13-15
NewMoon
Si interessa
 
Messaggi: 58
Iscritto il: mercoledì 20 ottobre 2010, 14:17

AoE in siege zone : attack ally as well

Messaggioda Jumbo » venerdì 6 maggio 2011, 13:16

Given the information from Lineage2.com

"Castle Sieges

Alliances will no longer be recognized as friendly forces on the battlefield.
During a castle siege, alliances can now register as opposing forces.
During a castle siege, clans on opposing sides can still form an alliance.
When a clan succeeds engraving the Holy Artifact during the castle siege, the alliances of that clan who registered as siege forces will now stay as siege forces. They do not automatically switch to the defending side and will be moved to the restart point outside the castle."

The AoE offensive skill should apply to ally as well and the only one who shouldn't be targeted would be people of the same side for the fight, the clan and the party.
This should only apply to siege_zone and command channel shouldn't prevent the AoE to hit people.

So the change to be made are in L2Skill.java
function name "public static final boolean checkForAreaOffensiveSkills(L2Character caster, L2Character target, L2Skill skill, boolean sourceInArena)" :


We don't want the command channel to be a solution to the ally not in the same side for the siege :
Codice: Seleziona tutto
                // Same commandchannel
                if (player.getParty().getCommandChannel() != null
                      && player.getParty().getCommandChannel() == targetPlayer.getParty().getCommandChannel())
                   return false;


changed to

Codice: Seleziona tutto
                // Same commandchannel
                if (player.getParty().getCommandChannel() != null
                      && player.getParty().getCommandChannel() == targetPlayer.getParty().getCommandChannel()
                      && !(player.isInsideZone(L2Character.ZONE_SIEGE)))
                   return false;



As we already tested if the caster and the possible target are in the same side for the siege. We only need to check if the player isn't in siege zone to forbide him as target.



And we have to make ally right target in case they are in siege zone.

Codice: Seleziona tutto
                if (player.getAllyId() != 0 && player.getAllyId() == targetPlayer.getAllyId())
                   return false;


should be changed to :

Codice: Seleziona tutto
                if (player.getAllyId() != 0 && player.getAllyId() == targetPlayer.getAllyId()
                   && !player.isInsideZone(L2Character.ZONE_SIEGE))
                   return false;


Added that if the caster is outside siege zone only, then ally shouldn't be targeted. Again, as the test for same side in siege zone was tested, no need to do a bigger test.

I only test the player, don't know if we need to test the target as well... maybe, maybe not. Shouldn't change too much the result.
Jumbo
Si interessa
 
Messaggi: 60
Iscritto il: sabato 9 aprile 2011, 14:30

summon fix

Messaggioda Jumbo » martedì 10 maggio 2011, 21:21

this will solve point 3 from : viewtopic.php?p=710786#p710786
(long discussion here : http://www.l2jserver.com/forum/viewtopi ... 69&t=21691)
Support for summon system, summon on login and restore buffs.

Features

Servitor/pet summons on login if player had it summoned before logout. With Config
Servitor/pet buffs are stored in DB when the servitor is unsummoned or when the owner logs out, and they are restored when summoning the servitor back. With config
Noblesse Blessing has the same effects it has for players for pets/servitors now, if the pet/servitor dies having it, its buffs are restored after resurrection
Caching servitor/pets buffs when player summons

files after tests:
summonsDP.patch
Codice: Seleziona tutto
### Eclipse Workspace Patch 1.0
#P L2J_DataPack_BETA
Index: sql/server/character_pet_skills_save.sql
===================================================================
--- sql/server/character_pet_skills_save.sql   (revisión: 0)
+++ sql/server/character_pet_skills_save.sql   (revisión: 0)
@@ -0,0 +1,9 @@
+CREATE TABLE IF NOT EXISTS `character_pet_skills_save` (
+  `petObjItemId` INT NOT NULL default 0,
+  `skill_id` INT NOT NULL default 0,
+  `skill_level` INT(3) NOT NULL default 1,
+  `effect_count` INT NOT NULL default 0,
+  `effect_cur_time` INT NOT NULL default 0,
+  `buff_index` INT(2) NOT NULL default 0,
+  PRIMARY KEY (`petObjItemId`,`skill_id`,`skill_level`)
+);
\ No newline at end of file
Index: tools/full_install.sql
===================================================================
--- tools/full_install.sql   (revisión: 7920)
+++ tools/full_install.sql   (copia de trabajo)
@@ -31,6 +31,7 @@
 DROP TABLE IF EXISTS character_quest_global_data;
 DROP TABLE IF EXISTS character_offline_trade_items;
 DROP TABLE IF EXISTS character_offline_trade;
+DROP TABLE IF EXISTS character_pet_skills_save;
 DROP TABLE IF EXISTS character_quests;
 DROP TABLE IF EXISTS character_raid_points;
 DROP TABLE IF EXISTS character_recipebook;
@@ -40,6 +41,8 @@
 DROP TABLE IF EXISTS character_skills;
 DROP TABLE IF EXISTS character_skills_save;
 DROP TABLE IF EXISTS character_subclasses;
+DROP TABLE IF EXISTS character_summons;
+DROP TABLE IF EXISTS character_summon_skills_save;
 DROP TABLE IF EXISTS character_tpbookmark;
 DROP TABLE IF EXISTS character_ui_actions;
 DROP TABLE IF EXISTS character_ui_categories;
Index: sql/server/pets.sql
===================================================================
--- sql/server/pets.sql   (revisión: 7920)
+++ sql/server/pets.sql   (copia de trabajo)
@@ -7,5 +7,7 @@
   `exp` decimal(20, 0) ,
   `sp` decimal(11) ,
   `fed` decimal(11) ,
+  `ownerId` decimal(11) NOT NULL default 0,
+  `restore` enum('true','false') NOT NULL DEFAULT 'false',
   PRIMARY KEY (`item_obj_id`)
 );
\ No newline at end of file
Index: sql/server/character_summons.sql
===================================================================
--- sql/server/character_summons.sql   (revisión: 0)
+++ sql/server/character_summons.sql   (revisión: 0)
@@ -0,0 +1,8 @@
+CREATE TABLE IF NOT EXISTS `character_summons` (
+  `ownerId` INT UNSIGNED NOT NULL DEFAULT 0,
+  `summonSkillId` INT UNSIGNED NOT NULL DEFAULT 0,
+  `curHp` MEDIUMINT UNSIGNED DEFAULT NULL,
+  `curMp` MEDIUMINT UNSIGNED DEFAULT NULL,
+  `time` decimal(11),
+  PRIMARY KEY (`ownerId`,`summonSkillId`)
+);
\ No newline at end of file
Index: sql/server/character_summon_skills_save.sql
===================================================================
--- sql/server/character_summon_skills_save.sql   (revisión: 0)
+++ sql/server/character_summon_skills_save.sql   (revisión: 0)
@@ -0,0 +1,11 @@
+CREATE TABLE IF NOT EXISTS `character_summon_skills_save` (
+  `ownerId` INT NOT NULL default 0,
+  `ownerClassIndex` INT(1) NOT NULL DEFAULT 0,
+  `summonSkillId` INT NOT NULL default 0,
+  `skill_id` INT NOT NULL default 0,
+  `skill_level` INT(3) NOT NULL default 1,
+  `effect_count` INT NOT NULL default 0,
+  `effect_cur_time` INT NOT NULL default 0,
+  `buff_index` INT(2) NOT NULL default 0,
+  PRIMARY KEY (`ownerId`,`ownerClassIndex`,`summonSkillId`,`skill_id`,`skill_level`)
+);
\ No newline at end of file

and summonsGS.patch


Codice: Seleziona tutto
### Eclipse Workspace Patch 1.0
#P L2J_Server_BETA
Index: java/config/Character.properties
===================================================================
--- java/config/Character.properties   (revision 4606)
+++ java/config/Character.properties   (working copy)
@@ -134,7 +134,7 @@
 
 # This option is to enable or disable the storage of buffs/debuffs among other effects during
 # a subclass change
-# Deault: False
+# Default: False
 SubclassStoreSkillCooltime = False
 
 # These are alternative rules for shields.
@@ -211,6 +211,22 @@
 # Default: False
 AltSubclassEverywhere = False
 
+
+# ---------------------------------------------------------------------------
+# Summons configuration
+# ---------------------------------------------------------------------------
+# This option is to enable or disable the storage of buffs/debuffs among other effects on pets/invocations
+# Default: True
+SummonStoreSkillCooltime = True
+
+# Servitor summons on login if player had it summoned before logout
+# Default: True
+RestoreServitorOnReconnect = True
+
+# Pet summons on login if player had it summoned before logout
+# Default: True
+RestorePetOnReconnect = True
+
 # ---------------------------------------------------------------------------
 # Vitality configuration
 # ---------------------------------------------------------------------------
Index: java/com/l2jserver/gameserver/GameServer.java
===================================================================
--- java/com/l2jserver/gameserver/GameServer.java   (revision 4606)
+++ java/com/l2jserver/gameserver/GameServer.java   (working copy)
@@ -39,6 +39,7 @@
 import com.l2jserver.gameserver.datatables.ArmorSetsTable;
 import com.l2jserver.gameserver.datatables.AugmentationData;
 import com.l2jserver.gameserver.datatables.CharNameTable;
+import com.l2jserver.gameserver.datatables.CharSummonTable;
 import com.l2jserver.gameserver.datatables.CharTemplateTable;
 import com.l2jserver.gameserver.datatables.ClanTable;
 import com.l2jserver.gameserver.datatables.DoorTable;
@@ -249,6 +250,7 @@
       GmListTable.getInstance();
       RaidBossPointsManager.getInstance();
       PetDataTable.getInstance();
+      CharSummonTable.getInstance().init();
       
       printSection("Clans");
       ClanTable.getInstance();
Index: java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java
===================================================================
--- java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java   (revision 4606)
+++ java/com/l2jserver/gameserver/model/actor/instance/L2PcInstance.java   (working copy)
@@ -60,6 +60,7 @@
 import com.l2jserver.gameserver.datatables.AccessLevels;
 import com.l2jserver.gameserver.datatables.AdminCommandAccessRights;
 import com.l2jserver.gameserver.datatables.CharNameTable;
+import com.l2jserver.gameserver.datatables.CharSummonTable;
 import com.l2jserver.gameserver.datatables.CharTemplateTable;
 import com.l2jserver.gameserver.datatables.ClanTable;
 import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
@@ -4199,7 +4200,7 @@
          }
          case SUMMON:
          {
-            if (!((L2SkillSummon)skill).isCubic() && (getPet() != null || isMounted()))
+            if (!((L2SkillSummon)skill).isCubic() && (getPet() != null || isMounted() || CharSummonTable.getInstance().getPets().contains(getObjectId()) || CharSummonTable.getInstance().getPets().contains(getObjectId())))
             {
                if (Config.DEBUG)
                   _log.fine("player has a pet already. ignore summon skill");
@@ -10733,6 +10734,9 @@
          _charges.set(0);
          stopChargeTask();
          
+         if (getPet() instanceof L2SummonInstance)
+            getPet().unSummon(this);
+         
          if (classIndex == 0)
          {
             setClassTemplate(getBaseClass());
@@ -10766,12 +10770,8 @@
           * 7. Reset HP/MP/CP stats and send Server->Client character status packet to reflect changes.
           * 8. Restore shortcut data related to this class.
           * 9. Resend a class change animation effect to broadcast to all nearby players.
-          * 10.Unsummon any active servitor from the player.
           */
          
-         if (getPet() instanceof L2SummonInstance)
-            getPet().unSummon(this);
-         
          for (L2Skill oldSkill : getAllSkills())
             super.removeSkill(oldSkill);
          
@@ -11099,7 +11099,14 @@
    public void onActionRequest()
    {
       if (isSpawnProtected())
+      {
          sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_NO_LONGER_PROTECTED_FROM_AGGRESSIVE_MONSTERS));
+         
+         if (Config.RESTORE_SERVITOR_ON_RECONNECT && getPet() == null && CharSummonTable.getInstance().getServitors().containsKey(getObjectId()))
+            CharSummonTable.getInstance().restoreServitor(this);
+         if (Config.RESTORE_PET_ON_RECONNECT && getPet() == null && CharSummonTable.getInstance().getPets().containsKey(getObjectId()))
+            CharSummonTable.getInstance().restorePet(this);
+      }
       if (isTeleportProtected())
          sendMessage("Teleport spawn protection ended.");
       setProtection(false);
@@ -11739,6 +11746,9 @@
       {
          try
          {
+            
+            getPet().setRestoreSummon(true);
+            
             getPet().unSummon(this);
             // dead pet wasnt unsummoned, broadcast npcinfo changes (pet will be without owner name - means owner offline)
             if (getPet() != null)
Index: java/com/l2jserver/gameserver/skills/l2skills/L2SkillSummon.java
===================================================================
--- java/com/l2jserver/gameserver/skills/l2skills/L2SkillSummon.java   (revision 4606)
+++ java/com/l2jserver/gameserver/skills/l2skills/L2SkillSummon.java   (working copy)
@@ -300,4 +300,14 @@
    {
       return _itemConsumeTime;
    }
+   
+   public final int getNpcId()
+   {
+      return _npcId;
+   }
+   
+   public final float getExpPenalty()
+   {
+      return _expPenalty;
+   }
 }
Index: java/com/l2jserver/gameserver/model/actor/instance/L2PetInstance.java
===================================================================
--- java/com/l2jserver/gameserver/model/actor/instance/L2PetInstance.java   (revision 4606)
+++ java/com/l2jserver/gameserver/model/actor/instance/L2PetInstance.java   (working copy)
@@ -17,6 +17,7 @@
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
+import java.util.List;
 import java.util.concurrent.Future;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -27,14 +28,18 @@
 import com.l2jserver.L2DatabaseFactory;
 import com.l2jserver.gameserver.ThreadPoolManager;
 import com.l2jserver.gameserver.ai.CtrlIntention;
+import com.l2jserver.gameserver.datatables.CharSummonTable;
 import com.l2jserver.gameserver.datatables.ItemTable;
 import com.l2jserver.gameserver.datatables.PetDataTable;
 import com.l2jserver.gameserver.datatables.SkillTable;
+import com.l2jserver.gameserver.datatables.SummonEffectsTable;
+import com.l2jserver.gameserver.datatables.SummonEffectsTable.SummonEffect;
 import com.l2jserver.gameserver.handler.IItemHandler;
 import com.l2jserver.gameserver.handler.ItemHandler;
 import com.l2jserver.gameserver.idfactory.IdFactory;
 import com.l2jserver.gameserver.instancemanager.CursedWeaponsManager;
 import com.l2jserver.gameserver.instancemanager.ItemsOnGroundManager;
+import com.l2jserver.gameserver.model.L2Effect;
 import com.l2jserver.gameserver.model.L2ItemInstance;
 import com.l2jserver.gameserver.model.L2Object;
 import com.l2jserver.gameserver.model.L2PetData;
@@ -54,9 +59,11 @@
 import com.l2jserver.gameserver.network.serverpackets.StatusUpdate;
 import com.l2jserver.gameserver.network.serverpackets.StopMove;
 import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
+import com.l2jserver.gameserver.skills.Env;
 import com.l2jserver.gameserver.skills.Stats;
 import com.l2jserver.gameserver.taskmanager.DecayTaskManager;
 import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
+import com.l2jserver.gameserver.templates.effects.EffectTemplate;
 import com.l2jserver.gameserver.templates.item.L2EtcItemType;
 import com.l2jserver.gameserver.templates.item.L2Item;
 import com.l2jserver.gameserver.templates.item.L2Weapon;
@@ -74,6 +81,10 @@
 {
    protected static final Logger _logPet = Logger.getLogger(L2PetInstance.class.getName());
    
+   private static final String ADD_SKILL_SAVE = "INSERT INTO character_pet_skills_save (petObjItemId,skill_id,skill_level,effect_count,effect_cur_time,buff_index) VALUES (?,?,?,?,?,?)";
+   private static final String RESTORE_SKILL_SAVE = "SELECT petObjItemId,skill_id,skill_level,effect_count,effect_cur_time,buff_index FROM character_pet_skills_save WHERE petObjItemId=? ORDER BY buff_index ASC";
+   private static final String DELETE_SKILL_SAVE = "DELETE FROM character_pet_skills_save WHERE petObjItemId=?";
+
    private int _curFed;
    private PetInventory _inventory;
    private final int _controlObjectId;
@@ -855,6 +866,12 @@
    }
    
    @Override
+   public void setRestoreSummon(boolean val)
+   {
+      _restoreSummon = val;
+   }
+   
+   @Override
    public void store()
    {
       if (getControlObjectId() == 0)
@@ -863,12 +880,15 @@
          return;
       }
       
+      if (!Config.RESTORE_PET_ON_RECONNECT)
+         _restoreSummon = false;
+      
       String req;
       if (!isRespawned())
-         req = "INSERT INTO pets (name,level,curHp,curMp,exp,sp,fed,item_obj_id) "+
-         "VALUES (?,?,?,?,?,?,?,?)";
+         req = "INSERT INTO pets (name,level,curHp,curMp,exp,sp,fed,ownerId,restore,item_obj_id) "+
+         "VALUES (?,?,?,?,?,?,?,?,?,?)";
       else
-         req = "UPDATE pets SET name=?,level=?,curHp=?,curMp=?,exp=?,sp=?,fed=? "+
+         req = "UPDATE pets SET name=?,level=?,curHp=?,curMp=?,exp=?,sp=?,fed=?,ownerId=?,restore=? "+
          "WHERE item_obj_id = ?";
       Connection con = null;
       try
@@ -882,10 +902,18 @@
          statement.setLong(5, getStat().getExp());
          statement.setInt(6, getStat().getSp());
          statement.setInt(7, getCurrentFed());
-         statement.setInt(8, getControlObjectId());
+         statement.setInt(8, getOwner().getObjectId());
+         statement.setString(9, String.valueOf(_restoreSummon)); // True restores pet on login
+         statement.setInt(10, getControlObjectId());
+         
          statement.executeUpdate();
          statement.close();
          _respawned = true;
+         
+         if (_restoreSummon)
+            CharSummonTable.getInstance().getPets().put(getOwner().getObjectId(), getControlObjectId());
+         else
+            CharSummonTable.getInstance().getPets().remove(getOwner().getObjectId());
       }
       catch (Exception e)
       {
@@ -904,6 +932,159 @@
       }
    }
    
+   @Override
+   public void storeEffect(boolean storeEffects)
+   {
+      if (!Config.SUMMON_STORE_SKILL_COOLTIME)
+         return;
+      
+      // Clear list for overwrite
+      if (SummonEffectsTable.getInstance().getPetEffects().contains(getControlObjectId()))
+         SummonEffectsTable.getInstance().getPetEffects().get(getControlObjectId()).clear();
+      
+      Connection con = null;
+      try
+      {
+         con = L2DatabaseFactory.getInstance().getConnection();
+         
+         // Delete all current stored effects for summon to avoid dupe
+         PreparedStatement statement = con.prepareStatement(DELETE_SKILL_SAVE);
+         
+         statement.setInt(1, getControlObjectId());
+         statement.execute();
+         statement.close();
+         
+         int buff_index = 0;
+         
+         final List<Integer> storedSkills = new FastList<Integer>();
+         
+         //Store all effect data along with calculated remaining
+         statement = con.prepareStatement(ADD_SKILL_SAVE);
+         
+         if (storeEffects)
+         {
+            for (L2Effect effect : getAllEffects())
+            {
+               if (effect == null)
+                  continue;
+               
+               switch (effect.getEffectType())
+               {
+                  case HEAL_OVER_TIME:
+                  case COMBAT_POINT_HEAL_OVER_TIME:
+                     // TODO: Fix me.
+                  case HIDE:
+                     continue;
+               }
+               
+               L2Skill skill = effect.getSkill();
+               if (storedSkills.contains(skill.getReuseHashCode()))
+                  continue;
+               
+               storedSkills.add(skill.getReuseHashCode());
+               
+               if (!effect.isHerbEffect() && effect.getInUse() && !skill.isToggle())
+               {
+                  statement.setInt(1, getControlObjectId());
+                  statement.setInt(2, skill.getId());
+                  statement.setInt(3, skill.getLevel());
+                  statement.setInt(4, effect.getCount());
+                  statement.setInt(5, effect.getTime());
+                  statement.setInt(6, ++buff_index);
+                  statement.execute();
+                  
+                  if (!SummonEffectsTable.getInstance().getPetEffects().contains(getControlObjectId()))
+                     SummonEffectsTable.getInstance().getPetEffects().put(getControlObjectId(), new FastList<SummonEffect>());
+
+                  SummonEffectsTable.getInstance().getPetEffects().get(getControlObjectId()).add(SummonEffectsTable.getInstance().new SummonEffect(skill, effect.getCount(), effect.getTime()));
+               }
+            }
+            statement.close();
+         }
+      }
+      catch (Exception e)
+      {
+         _log.log(Level.WARNING, "Could not store pet effect data: ", e);
+      }
+      finally
+      {
+         L2DatabaseFactory.close(con);
+      }
+   }
+   
+   @Override
+   public void restoreEffects()
+   {
+      Connection con = null;
+      PreparedStatement statement = null;
+      try
+      {
+         con = L2DatabaseFactory.getInstance().getConnection();
+
+         if (!SummonEffectsTable.getInstance().getPetEffects().contains(getControlObjectId()))
+         {
+            statement = con.prepareStatement(RESTORE_SKILL_SAVE);
+            statement.setInt(1, getControlObjectId());
+            ResultSet rset = statement.executeQuery();
+            
+            while (rset.next())
+            {
+               int effectCount = rset.getInt("effect_count");
+               int effectCurTime = rset.getInt("effect_cur_time");
+               
+               final L2Skill skill = SkillTable.getInstance().getInfo(rset.getInt("skill_id"), rset.getInt("skill_level"));
+               if (skill == null)
+                  continue;
+               
+               if (skill.hasEffects())
+               {
+                  if (!SummonEffectsTable.getInstance().getPetEffects().contains(getControlObjectId()))
+                     SummonEffectsTable.getInstance().getPetEffects().put(getControlObjectId(), new FastList<SummonEffect>());
+                  
+                  SummonEffectsTable.getInstance().getPetEffects().get(getControlObjectId()).add(SummonEffectsTable.getInstance().new SummonEffect(skill, effectCount, effectCurTime));
+               }
+            }
+            
+            rset.close();
+            statement.close();
+         }
+         statement = con.prepareStatement(DELETE_SKILL_SAVE);
+         statement.setInt(1, getControlObjectId());
+         statement.executeUpdate();
+         statement.close();
+      }
+      catch (Exception e)
+      {
+         _log.log(Level.WARNING, "Could not restore " + this + " active effect data: " + e.getMessage(), e);
+      }
+      finally
+      {
+         L2DatabaseFactory.close(con);
+         
+         if (SummonEffectsTable.getInstance().getPetEffects().get(getControlObjectId()) == null)
+            return;
+
+         for (SummonEffect se : SummonEffectsTable.getInstance().getPetEffects().get(getControlObjectId()))
+         {
+            Env env = new Env();
+            env.player = this;
+            env.target = this;
+            env.skill = se.getSkill();
+            L2Effect ef;
+            for (EffectTemplate et : se.getSkill().getEffectTemplates())
+            {
+               ef = et.getEffect(env);
+               if (ef != null)
+               {
+                  ef.setCount(se.getEffectCount());
+                  ef.setFirstTime(se.getEffectCurTime());
+                  ef.scheduleEffect();
+               }
+            }
+         }
+      }
+   }
+   
    public synchronized void stopFeed()
    {
       if (_feedTask != null)
Index: java/com/l2jserver/Config.java
===================================================================
--- java/com/l2jserver/Config.java   (revision 4606)
+++ java/com/l2jserver/Config.java   (working copy)
@@ -116,6 +116,7 @@
    public static int PLAYER_FAKEDEATH_UP_PROTECTION;
    public static boolean STORE_SKILL_COOLTIME;
    public static boolean SUBCLASS_STORE_SKILL_COOLTIME;
+   public static boolean SUMMON_STORE_SKILL_COOLTIME;
    public static boolean ALT_GAME_SHIELD_BLOCKS;
    public static int ALT_PERFECT_SHLD_BLOCK;
    public static boolean ALLOW_CLASS_MASTERS;
@@ -129,6 +130,8 @@
    public static boolean ALT_GAME_SKILL_LEARN;
    public static boolean ALT_GAME_SUBCLASS_WITHOUT_QUESTS;
    public static boolean ALT_GAME_SUBCLASS_EVERYWHERE;
+   public static boolean RESTORE_SERVITOR_ON_RECONNECT;
+   public static boolean RESTORE_PET_ON_RECONNECT;
    public static int MAX_RUN_SPEED;
    public static int MAX_PCRIT_RATE;
    public static int MAX_MCRIT_RATE;
@@ -1502,6 +1505,7 @@
                PLAYER_FAKEDEATH_UP_PROTECTION = Integer.parseInt(Character.getProperty("PlayerFakeDeathUpProtection", "0"));
                STORE_SKILL_COOLTIME = Boolean.parseBoolean(Character.getProperty("StoreSkillCooltime", "true"));
                SUBCLASS_STORE_SKILL_COOLTIME = Boolean.parseBoolean(Character.getProperty("SubclassStoreSkillCooltime", "false"));
+               SUMMON_STORE_SKILL_COOLTIME = Boolean.parseBoolean(Character.getProperty("SummonStoreSkillCooltime", "True"));
                ALT_GAME_SHIELD_BLOCKS = Boolean.parseBoolean(Character.getProperty("AltShieldBlocks", "false"));
                ALT_PERFECT_SHLD_BLOCK = Integer.parseInt(Character.getProperty("AltPerfectShieldBlockRate", "10"));
                ALLOW_CLASS_MASTERS = Boolean.parseBoolean(Character.getProperty("AllowClassMasters", "False"));
@@ -1515,7 +1519,9 @@
                DIVINE_SP_BOOK_NEEDED = Boolean.parseBoolean(Character.getProperty("DivineInspirationSpBookNeeded", "true"));
                ALT_GAME_SKILL_LEARN = Boolean.parseBoolean(Character.getProperty("AltGameSkillLearn", "false"));
                ALT_GAME_SUBCLASS_WITHOUT_QUESTS = Boolean.parseBoolean(Character.getProperty("AltSubClassWithoutQuests", "False"));
-               ALT_GAME_SUBCLASS_EVERYWHERE = Boolean.parseBoolean(Character.getProperty("AltSubclassEverywhere", "False"));
+               ALT_GAME_SUBCLASS_EVERYWHERE = Boolean.parseBoolean(Character.getProperty("AltSubclassEverywhere", "True"));
+               RESTORE_SERVITOR_ON_RECONNECT = Boolean.parseBoolean(Character.getProperty("RestoreServitorOnReconnect", "true"));
+               RESTORE_PET_ON_RECONNECT = Boolean.parseBoolean(Character.getProperty("RestorePetOnReconnect", "False"));
                ENABLE_VITALITY = Boolean.parseBoolean(Character.getProperty("EnableVitality", "True"));
                RECOVER_VITALITY_ON_RECONNECT = Boolean.parseBoolean(Character.getProperty("RecoverVitalityOnReconnect", "True"));
                STARTING_VITALITY_POINTS = Integer.parseInt(Character.getProperty("StartingVitalityPoints", "20000"));
Index: java/com/l2jserver/gameserver/model/actor/instance/L2SummonInstance.java
===================================================================
--- java/com/l2jserver/gameserver/model/actor/instance/L2SummonInstance.java   (revision 4606)
+++ java/com/l2jserver/gameserver/model/actor/instance/L2SummonInstance.java   (working copy)
@@ -14,26 +14,45 @@
  */
 package com.l2jserver.gameserver.model.actor.instance;
 
+import gnu.trove.TIntObjectHashMap;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.List;
 import java.util.concurrent.Future;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javolution.util.FastList;
+
 import com.l2jserver.Config;
+import com.l2jserver.L2DatabaseFactory;
 import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.datatables.CharSummonTable;
 import com.l2jserver.gameserver.datatables.SkillTable;
+import com.l2jserver.gameserver.datatables.SummonEffectsTable;
+import com.l2jserver.gameserver.datatables.SummonEffectsTable.SummonEffect;
+import com.l2jserver.gameserver.model.L2Effect;
 import com.l2jserver.gameserver.model.L2Object;
 import com.l2jserver.gameserver.model.L2Skill;
 import com.l2jserver.gameserver.model.actor.L2Character;
 import com.l2jserver.gameserver.model.actor.L2Summon;
 import com.l2jserver.gameserver.network.serverpackets.SetSummonRemainTime;
+import com.l2jserver.gameserver.skills.Env;
 import com.l2jserver.gameserver.skills.l2skills.L2SkillSummon;
 import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
+import com.l2jserver.gameserver.templates.effects.EffectTemplate;
 
 
 public class L2SummonInstance extends L2Summon
 {
    protected static final Logger log = Logger.getLogger(L2SummonInstance.class.getName());
    
+   private static final String ADD_SKILL_SAVE = "INSERT INTO character_summon_skills_save (ownerId,ownerClassIndex,summonSkillId,skill_id,skill_level,effect_count,effect_cur_time,buff_index) VALUES (?,?,?,?,?,?,?,?)";
+   private static final String RESTORE_SKILL_SAVE = "SELECT skill_id,skill_level,effect_count,effect_cur_time,buff_index FROM character_summon_skills_save WHERE ownerId=? AND ownerClassIndex=? AND summonSkillId=? ORDER BY buff_index ASC";
+   private static final String DELETE_SKILL_SAVE = "DELETE FROM character_summon_skills_save WHERE ownerId=? AND ownerClassIndex=? AND summonSkillId=?";
+
    private float _expPenalty = 0; // exp decrease multiplier (i.e. 0.3 (= 30%) for shadow)
    private int _itemConsumeId;
    private int _itemConsumeCount;
@@ -47,6 +66,8 @@
    
    private Future<?> _summonLifeTask;
    
+   private int _referenceSkill;
+   
    public L2SummonInstance(int objectId, L2NpcTemplate template, L2PcInstance owner, L2Skill skill)
    {
       super(objectId, template, owner);
@@ -62,6 +83,7 @@
          _totalLifeTime = summonSkill.getTotalLifeTime();
          _timeLostIdle = summonSkill.getTimeLostIdle();
          _timeLostActive = summonSkill.getTimeLostActive();
+         _referenceSkill = summonSkill.getId();
       }
       else
       {
@@ -191,6 +213,9 @@
          _summonLifeTask.cancel(false);
          _summonLifeTask = null;
       }
+      
+      CharSummonTable.getInstance().removeServitor(getOwner());
+      
       return true;
       
    }
@@ -223,6 +248,210 @@
          super.doCast(skill);
    }
    
+   @Override
+   public void setRestoreSummon(boolean val)
+   {
+      _restoreSummon = val;
+   }
+   
+   @Override
+   public void store()
+   {
+      if (_referenceSkill == 0 || isDead())
+         return;
+      
+      if (Config.RESTORE_SERVITOR_ON_RECONNECT)
+         CharSummonTable.getInstance().saveSummon(this);
+   }
+   
+   @Override
+   public void storeEffect(boolean storeEffects)
+   {
+      if (!Config.SUMMON_STORE_SKILL_COOLTIME)
+         return;
+      
+      if (getOwner().isInOlympiadMode())
+         return;
+      
+      // Clear list for overwrite
+      if (
+            SummonEffectsTable.getInstance().getServitorEffectsOwner().contains(getOwner().getObjectId()) &&
+            SummonEffectsTable.getInstance().getServitorEffectsOwner().get(getOwner().getObjectId()).contains(getOwner().getClassIndex()) &&
+            SummonEffectsTable.getInstance().getServitorEffects(getOwner()).contains(getReferenceSkill())
+         )
+         SummonEffectsTable.getInstance().getServitorEffects(getOwner()).get(getReferenceSkill()).clear();
+      
+      Connection con = null;
+      try
+      {
+         con = L2DatabaseFactory.getInstance().getConnection();
+         
+         // Delete all current stored effects for summon to avoid dupe
+         PreparedStatement statement = con.prepareStatement(DELETE_SKILL_SAVE);
+         
+         statement.setInt(1, getOwner().getObjectId());
+         statement.setInt(2, getOwner().getClassIndex());
+         statement.setInt(3, getReferenceSkill());
+         
+         statement.execute();
+         statement.close();
+         
+         int buff_index = 0;
+         
+         final List<Integer> storedSkills = new FastList<Integer>();
+         
+         //Store all effect data along with calculated remaining
+         statement = con.prepareStatement(ADD_SKILL_SAVE);
+         
+         if (storeEffects)
+         {
+            for (L2Effect effect : getAllEffects())
+            {
+               if (effect == null)
+                  continue;
+               
+               switch (effect.getEffectType())
+               {
+                  case HEAL_OVER_TIME:
+                  case COMBAT_POINT_HEAL_OVER_TIME:
+                     // TODO: Fix me.
+                  case HIDE:
+                     continue;
+               }
+               
+               L2Skill skill = effect.getSkill();
+               if (storedSkills.contains(skill.getReuseHashCode()))
+                  continue;
+               
+               storedSkills.add(skill.getReuseHashCode());
+               
+               if (!effect.isHerbEffect() && effect.getInUse() && !skill.isToggle())
+               {
+                  statement.setInt(1, getOwner().getObjectId());
+                  statement.setInt(2, getOwner().getClassIndex());
+                  statement.setInt(3, getReferenceSkill());
+                  statement.setInt(4, skill.getId());
+                  statement.setInt(5, skill.getLevel());
+                  statement.setInt(6, effect.getCount());
+                  statement.setInt(7, effect.getTime());
+                  statement.setInt(8, ++buff_index);
+                  statement.execute();
+                  
+                  if (!SummonEffectsTable.getInstance().getServitorEffectsOwner().contains(getOwner().getObjectId())) // Check if charId exists in map
+                     SummonEffectsTable.getInstance().getServitorEffectsOwner().put(getOwner().getObjectId(), new TIntObjectHashMap<TIntObjectHashMap<List<SummonEffect>>>());
+                  if (!SummonEffectsTable.getInstance().getServitorEffectsOwner().get(getOwner().getObjectId()).contains(getOwner().getClassIndex())) // Check if classIndex exists in charId map
+                     SummonEffectsTable.getInstance().getServitorEffectsOwner().get(getOwner().getObjectId()).put(getOwner().getClassIndex(), new TIntObjectHashMap<List<SummonEffect>>());
+                  if (!SummonEffectsTable.getInstance().getServitorEffects(getOwner()).contains(getReferenceSkill())) // Check is summonSkillId exists in charId+classIndex map
+                     SummonEffectsTable.getInstance().getServitorEffects(getOwner()).put(getReferenceSkill(), new FastList<SummonEffect>());
+
+                  SummonEffectsTable.getInstance().getServitorEffects(getOwner()).get(getReferenceSkill()).add(SummonEffectsTable.getInstance().new SummonEffect(skill, effect.getCount(), effect.getTime()));
+
+               }
+            }
+            statement.close();
+         }
+      }
+      catch (Exception e)
+      {
+         _log.log(Level.WARNING, "Could not store summon effect data: ", e);
+      }
+      finally
+      {
+         L2DatabaseFactory.close(con);
+      }
+   }
+   
+   @Override
+   public void restoreEffects()
+   {
+      if (getOwner().isInOlympiadMode())
+         return;
+      
+      Connection con = null;
+      PreparedStatement statement = null;
+      try
+      {
+         con = L2DatabaseFactory.getInstance().getConnection();
+         if (
+               !SummonEffectsTable.getInstance().getServitorEffectsOwner().contains(getOwner().getObjectId()) ||
+               !SummonEffectsTable.getInstance().getServitorEffectsOwner().get(getOwner().getObjectId()).contains(getOwner().getClassIndex()) ||
+               !SummonEffectsTable.getInstance().getServitorEffects(getOwner()).contains(getReferenceSkill())
+            )
+         {
+            statement = con.prepareStatement(RESTORE_SKILL_SAVE);
+            statement.setInt(1, getOwner().getObjectId());
+            statement.setInt(2, getOwner().getClassIndex());
+            statement.setInt(3, getReferenceSkill());
+            ResultSet rset = statement.executeQuery();
+            
+            while (rset.next())
+            {
+               int effectCount = rset.getInt("effect_count");
+               int effectCurTime = rset.getInt("effect_cur_time");
+               
+               final L2Skill skill = SkillTable.getInstance().getInfo(rset.getInt("skill_id"), rset.getInt("skill_level"));
+               if (skill == null)
+                  continue;
+               
+               if (skill.hasEffects())
+               {
+                  if (!SummonEffectsTable.getInstance().getServitorEffectsOwner().contains(getOwner().getObjectId())) // Check if charId exists in map
+                     SummonEffectsTable.getInstance().getServitorEffectsOwner().put(getOwner().getObjectId(), new TIntObjectHashMap<TIntObjectHashMap<List<SummonEffect>>>());
+                  if (!SummonEffectsTable.getInstance().getServitorEffectsOwner().get(getOwner().getObjectId()).contains(getOwner().getClassIndex())) // Check if classIndex exists in charId map
+                     SummonEffectsTable.getInstance().getServitorEffectsOwner().get(getOwner().getObjectId()).put(getOwner().getClassIndex(), new TIntObjectHashMap<List<SummonEffect>>());
+                  if (!SummonEffectsTable.getInstance().getServitorEffects(getOwner()).contains(getReferenceSkill())) // Check is summonSkillId exists in charId+classIndex map
+                     SummonEffectsTable.getInstance().getServitorEffects(getOwner()).put(getReferenceSkill(), new FastList<SummonEffect>());
+                  
+                  SummonEffectsTable.getInstance().getServitorEffects(getOwner()).get(getReferenceSkill()).add(SummonEffectsTable.getInstance().new SummonEffect(skill, effectCount, effectCurTime));
+               }
+            }
+            
+            rset.close();
+            statement.close();
+         }
+         
+         statement = con.prepareStatement(DELETE_SKILL_SAVE);
+         statement.setInt(1, getOwner().getObjectId());
+         statement.setInt(2, getOwner().getClassIndex());
+         statement.setInt(3, getReferenceSkill());
+         statement.executeUpdate();
+         statement.close();
+      }
+      catch (Exception e)
+      {
+         _log.log(Level.WARNING, "Could not restore " + this + " active effect data: " + e.getMessage(), e);
+      }
+      finally
+      {
+         L2DatabaseFactory.close(con);
+         if (
+               !SummonEffectsTable.getInstance().getServitorEffectsOwner().contains(getOwner().getObjectId()) ||
+               !SummonEffectsTable.getInstance().getServitorEffectsOwner().get(getOwner().getObjectId()).contains(getOwner().getClassIndex()) ||
+               !SummonEffectsTable.getInstance().getServitorEffects(getOwner()).contains(getReferenceSkill())
+            )
+            return;
+
+         for (SummonEffect se : SummonEffectsTable.getInstance().getServitorEffects(getOwner()).get(getReferenceSkill()))
+         {
+            Env env = new Env();
+            env.player = this;
+            env.target = this;
+            env.skill = se.getSkill();
+            L2Effect ef;
+            for (EffectTemplate et : se.getSkill().getEffectTemplates())
+            {
+               ef = et.getEffect(env);
+               if (ef != null)
+               {
+                  ef.setCount(se.getEffectCount());
+                  ef.setFirstTime(se.getEffectCurTime());
+                  ef.scheduleEffect();
+               }
+            }
+         }
+      }
+   }
+   
    static class SummonLifetime implements Runnable
    {
       private L2PcInstance _activeChar;
@@ -300,6 +529,9 @@
       }
       
       super.unSummon(owner);
+      
+      if (!_restoreSummon)
+         CharSummonTable.getInstance().removeServitor(owner);
    }
    
    @Override
@@ -345,4 +577,14 @@
       // bonus from owner
       return super.getDefenseElementValue(attribute) + getOwner().getDefenseElementValue(attribute);
    }
+   
+   public void setTimeRemaining(int time)
+   {
+      _timeRemaining = time;
+   }
+   
+   public int getReferenceSkill()
+   {
+      return _referenceSkill;
+   }
 }
Index: java/com/l2jserver/gameserver/datatables/SummonEffectsTable.java
===================================================================
--- java/com/l2jserver/gameserver/datatables/SummonEffectsTable.java   (revision 0)
+++ java/com/l2jserver/gameserver/datatables/SummonEffectsTable.java   (revision 0)
@@ -0,0 +1,98 @@
+/*
+ * 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 com.l2jserver.gameserver.datatables;
+
+import gnu.trove.TIntObjectHashMap;
+
+import java.util.List;
+
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * @author Nyaran
+ */
+public class SummonEffectsTable
+{
+   /** Servitors **/
+   /*
+    * Map tree
+    * key: charObjectId, value: classIndex Map
+    *       key: classIndex, value: servitors Map
+    *          key: servitorSkillId, value: Effects list
+    */
+   private TIntObjectHashMap<TIntObjectHashMap<TIntObjectHashMap<List<SummonEffect>>>> _servitorEffects = new TIntObjectHashMap<TIntObjectHashMap<TIntObjectHashMap<List<SummonEffect>>>>();
+
+   public TIntObjectHashMap<TIntObjectHashMap<TIntObjectHashMap<List<SummonEffect>>>> getServitorEffectsOwner()
+   {
+      return _servitorEffects;
+   }
+   
+   public TIntObjectHashMap<List<SummonEffect>> getServitorEffects(L2PcInstance owner)
+   {
+      return _servitorEffects.get(owner.getObjectId()).get(owner.getClassIndex());
+   }
+   
+   
+   /** Pets **/
+   private TIntObjectHashMap<List<SummonEffect>> _petEffects = new TIntObjectHashMap<List<SummonEffect>>(); // key: petItemObjectId, value: Effects list
+   
+   public TIntObjectHashMap<List<SummonEffect>> getPetEffects()
+   {
+      return _petEffects;
+   }
+   
+   
+   /** Common **/
+   public static SummonEffectsTable getInstance()
+   {
+      return SingletonHolder._instance;
+   }
+   
+   public class SummonEffect
+   {
+      L2Skill _skill;
+      int _effectCount;
+      int _effectCurTime;
+      
+      public SummonEffect(L2Skill skill, int effectCount, int effectCurTime)
+      {
+         _skill = skill;
+         _effectCount = effectCount;
+         _effectCurTime = effectCurTime;
+      }
+      
+      public L2Skill getSkill()
+      {
+         return _skill;
+      }
+      
+      public int getEffectCount()
+      {
+         return _effectCount;
+      }
+      
+      public int getEffectCurTime()
+      {
+         return _effectCurTime;
+      }
+   }
+   
+   @SuppressWarnings("synthetic-access")
+   private static class SingletonHolder
+   {
+      protected static final SummonEffectsTable _instance = new SummonEffectsTable();
+   }
+}
Index: java/com/l2jserver/gameserver/datatables/CharSummonTable.java
===================================================================
--- java/com/l2jserver/gameserver/datatables/CharSummonTable.java   (revision 0)
+++ java/com/l2jserver/gameserver/datatables/CharSummonTable.java   (revision 0)
@@ -0,0 +1,327 @@
+/*
+ * 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 com.l2jserver.gameserver.datatables;
+
+import gnu.trove.TIntIntHashMap;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.l2jserver.Config;
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.idfactory.IdFactory;
+import com.l2jserver.gameserver.model.L2ItemInstance;
+import com.l2jserver.gameserver.model.L2SummonItem;
+import com.l2jserver.gameserver.model.actor.instance.L2MerchantSummonInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PetInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2SiegeSummonInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2SummonInstance;
+import com.l2jserver.gameserver.model.base.Experience;
+import com.l2jserver.gameserver.network.serverpackets.PetItemList;
+import com.l2jserver.gameserver.skills.l2skills.L2SkillSummon;
+import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
+
+/**
+ * @author Nyaran
+ */
+public class CharSummonTable
+{
+   private static Logger _log = Logger.getLogger(CharSummonTable.class.getName());
+   
+   private static final String INIT_SUMMONS = "SELECT ownerId, summonSkillId FROM character_summons";
+   private static final String INIT_PET = "SELECT ownerId, item_obj_id FROM pets WHERE restore = 'true'";
+
+   private static final String SAVE_SUMMON = "REPLACE INTO character_summons (ownerId,summonSkillId,curHp,curMp,time) VALUES (?,?,?,?,?)";
+   private static final String LOAD_SUMMON = "SELECT curHp, curMp, time FROM character_summons WHERE ownerId = ? AND summonSkillId = ?";
+   private static final String REMOVE_SUMMON = "DELETE FROM character_summons WHERE ownerId = ?";
+   
+   private static final TIntIntHashMap _servitors = new TIntIntHashMap();
+   private static final TIntIntHashMap _pets = new TIntIntHashMap();
+   
+   public static CharSummonTable getInstance()
+   {
+      return SingletonHolder._instance;
+   }
+   
+   public void init()
+   {
+      int ownerId;
+      int refId;
+      
+      Connection con = null;
+      
+      if (Config.RESTORE_SERVITOR_ON_RECONNECT)
+      {
+         try
+         {
+            con = L2DatabaseFactory.getInstance().getConnection();
+            PreparedStatement statement = con.prepareStatement(INIT_SUMMONS);
+            ResultSet rset = statement.executeQuery();
+            
+            while (rset.next())
+            {
+               ownerId = rset.getInt("ownerId");
+               refId = rset.getInt("summonSkillId");
+               
+               _servitors.put(ownerId, refId);
+            }
+            
+            rset.close();
+            statement.close();
+         }
+         catch (Exception e)
+         {
+            _log.log(Level.SEVERE, "Error while loading saved summons", e);
+         }
+         finally
+         {
+            L2DatabaseFactory.close(con);
+         }
+      }
+      
+      if (Config.RESTORE_PET_ON_RECONNECT)
+      {
+         try
+         {
+            con = L2DatabaseFactory.getInstance().getConnection();
+            PreparedStatement statement = con.prepareStatement(INIT_PET);
+            ResultSet rset = statement.executeQuery();
+            
+            while (rset.next())
+            {
+               ownerId = rset.getInt("ownerId");
+               refId = rset.getInt("item_obj_id");
+               
+               _pets.put(ownerId, refId);
+            }
+            
+            rset.close();
+            statement.close();
+         }
+         
+         catch (Exception e)
+         {
+            _log.log(Level.SEVERE, "Error while loading saved summons", e);
+         }
+         finally
+         {
+            L2DatabaseFactory.close(con);
+         }
+      }
+   }
+   
+   public TIntIntHashMap getServitors()
+   {
+      return _servitors;
+   }
+   
+   public TIntIntHashMap getPets()
+   {
+      return _pets;
+   }
+   
+   public void saveSummon(L2SummonInstance summon)
+   {
+      Connection con = null;
+      try
+      {
+         con = L2DatabaseFactory.getInstance().getConnection();
+         PreparedStatement statement = con.prepareStatement(SAVE_SUMMON);
+         
+         statement.setInt(1, summon.getOwner().getObjectId());
+         statement.setInt(2, summon.getReferenceSkill());
+         statement.setDouble(3, summon.getCurrentHp());
+         statement.setDouble(4, summon.getCurrentMp());
+         statement.setInt(5, summon.getTimeRemaining());
+         
+         statement.execute();
+         statement.close();
+         
+         _servitors.put(summon.getOwner().getObjectId(), summon.getReferenceSkill());
+      }
+      catch (Exception e)
+      {
+         _log.log(Level.SEVERE, "Failed to store summon [SummonId: " + summon.getNpcId() + "] from Char [CharId: " + summon.getOwner().getObjectId() + "] data", e);
+      }
+      finally
+      {
+         L2DatabaseFactory.close(con);
+      }
+   }
+   
+   public void restoreServitor(L2PcInstance activeChar)
+   {
+      Connection con = null;
+      try
+      {
+         int skillId = _servitors.get(activeChar.getObjectId());
+         
+         con = L2DatabaseFactory.getInstance().getConnection();
+         PreparedStatement statement = con.prepareStatement(LOAD_SUMMON);
+         statement.setInt(1, activeChar.getObjectId());
+         statement.setInt(2, skillId);
+         ResultSet rset = statement.executeQuery();
+         
+         L2NpcTemplate summonTemplate;
+         L2SummonInstance summon;
+         L2SkillSummon skill;
+         
+         while (rset.next())
+         {
+            int curHp = rset.getInt("curHp");
+            int curMp = rset.getInt("curMp");
+            int time = rset.getInt("time");
+            
+            skill = (L2SkillSummon) SkillTable.getInstance().getInfo(skillId, activeChar.getSkillLevel(skillId));
+            if (skill == null)
+            {
+               removeServitor(activeChar);
+               return;
+            }
+            
+            summonTemplate = NpcTable.getInstance().getTemplate(skill.getNpcId());
+            if (summonTemplate == null)
+            {
+               _log.warning("[CharSummonTable] Summon attemp for nonexisting Skill ID:" + skillId);
+               return;
+            }
+            
+            if (summonTemplate.type.equalsIgnoreCase("L2SiegeSummon"))
+               summon = new L2SiegeSummonInstance(IdFactory.getInstance().getNextId(), summonTemplate, activeChar, skill);
+            /* TODO: Confirm L2Merchant
+            else if (summonTemplate.type.equalsIgnoreCase("L2MerchantSummon"))
+               summon = new L2MerchantSummonInstance(IdFactory.getInstance().getNextId(), summonTemplate, activeChar, skill);*/
+            else
+               summon = new L2SummonInstance(IdFactory.getInstance().getNextId(), summonTemplate, activeChar, skill);
+            
+            summon.setName(summonTemplate.name);
+            summon.setTitle(activeChar.getName());
+            summon.setExpPenalty(skill.getExpPenalty());
+            
+            if (summon.getLevel() >= Experience.PET_MAX_LEVEL)
+            {
+               summon.getStat().setExp(Experience.LEVEL[Experience.PET_MAX_LEVEL - 1]);
+               _log.warning("Summon (" + summon.getName() + ") NpcID: " + summon.getNpcId() + " has a level above 86. Please rectify.");
+            }
+            else
+            {
+               summon.getStat().setExp(Experience.LEVEL[(summon.getLevel() % Experience.PET_MAX_LEVEL)]);
+            }
+            summon.setCurrentHp(curHp);
+            summon.setCurrentMp(curMp);
+            summon.setHeading(activeChar.getHeading());
+            summon.setRunning();
+            if (!(summon instanceof L2MerchantSummonInstance))
+               activeChar.setPet(summon);
+            
+            summon.setTimeRemaining(time);
+            
+            //L2World.getInstance().storeObject(summon);
+            summon.spawnMe(activeChar.getX() + 20, activeChar.getY() + 20, activeChar.getZ());
+         }
+         
+         rset.close();
+         statement.close();
+      }
+      catch (SQLException e)
+      {
+         _log.log(Level.WARNING, "[CharSummonTable]: Summon cannot be restored: ", e);
+      }
+      finally
+      {
+         L2DatabaseFactory.close(con);
+      }
+   }
+   
+   public void removeServitor(L2PcInstance activeChar)
+   {
+      Connection con = null;
+      try
+      {
+         con = L2DatabaseFactory.getInstance().getConnection();
+         PreparedStatement statement = con.prepareStatement(REMOVE_SUMMON);
+         statement.setInt(1, activeChar.getObjectId());
+         
+         statement.execute();
+         statement.close();
+         _servitors.remove(activeChar.getObjectId());
+      }
+      catch (SQLException e)
+      {
+         _log.log(Level.WARNING, "[CharSummonTable]: Summon cannot be removed: ", e);
+      }
+      finally
+      {
+         L2DatabaseFactory.close(con);
+      }
+   }
+   
+   public void restorePet(L2PcInstance activeChar)
+   {
+      L2ItemInstance item = activeChar.getInventory().getItemByObjectId(_pets.get(activeChar.getObjectId()));
+      final L2SummonItem sitem = SummonItemsData.getInstance().getSummonItem(item.getItemId());
+      L2NpcTemplate npcTemplate = NpcTable.getInstance().getTemplate(sitem.getNpcId());
+      
+      if (npcTemplate == null)
+         return;
+      
+      final L2PetInstance petSummon = L2PetInstance.spawnPet(npcTemplate, activeChar, item);
+      if (petSummon == null)
+         return;
+      
+      petSummon.setShowSummonAnimation(true);
+      petSummon.setTitle(activeChar.getName());
+      
+      if (!petSummon.isRespawned())
+      {
+         petSummon.setCurrentHp(petSummon.getMaxHp());
+         petSummon.setCurrentMp(petSummon.getMaxMp());
+         petSummon.getStat().setExp(petSummon.getExpForThisLevel());
+         petSummon.setCurrentFed(petSummon.getMaxFed());
+      }
+      
+      petSummon.setRunning();
+      
+      if (!petSummon.isRespawned())
+         petSummon.store();
+      
+      activeChar.setPet(petSummon);
+      
+      petSummon.spawnMe(activeChar.getX() + 50, activeChar.getY() + 100, activeChar.getZ());
+      petSummon.startFeed();
+      item.setEnchantLevel(petSummon.getLevel());
+      
+      if (petSummon.getCurrentFed() <= 0)
+         petSummon.unSummon(activeChar);
+      else
+         petSummon.startFeed();
+      
+      petSummon.setFollowStatus(true);
+      
+      petSummon.getOwner().sendPacket(new PetItemList(petSummon));
+      petSummon.broadcastStatusUpdate();
+   }
+   
+   @SuppressWarnings("synthetic-access")
+   private static class SingletonHolder
+   {
+      protected static final CharSummonTable _instance = new CharSummonTable();
+   }
+}
Index: java/com/l2jserver/gameserver/model/actor/L2Summon.java
===================================================================
--- java/com/l2jserver/gameserver/model/actor/L2Summon.java   (revision 4606)
+++ java/com/l2jserver/gameserver/model/actor/L2Summon.java   (working copy)
@@ -16,6 +16,7 @@
 
 import java.util.Collection;
 
+import com.l2jserver.Config;
 import com.l2jserver.gameserver.ai.CtrlIntention;
 import com.l2jserver.gameserver.ai.L2CharacterAI;
 import com.l2jserver.gameserver.ai.L2SummonAI;
@@ -73,6 +74,8 @@
    // we dont have walk speed in pet data so for now use runspd / 3
    public static final int WALK_SPEED_MULTIPLIER = 3;
    
+   public boolean _restoreSummon = true;
+   
    public class AIAccessor extends L2Character.AIAccessor
    {
       protected AIAccessor() {}
@@ -105,6 +108,9 @@
       super.onSpawn();
       if (!(this instanceof L2MerchantSummonInstance))
       {
+         if (Config.SUMMON_STORE_SKILL_COOLTIME)
+            restoreEffects();
+         
          this.setFollowStatus(true);
          updateAndBroadcastStatus(0);
          getOwner().sendPacket(new RelationChanged(this, getOwner().getRelation(getOwner()), false));
@@ -118,7 +124,7 @@
       }
       setShowSummonAnimation(false); // addVisibleObject created the info packets with summon animation
       // if someone comes into range now, the animation shouldnt show any more
-      
+      _restoreSummon = false;
    }
    
    @Override
@@ -296,6 +302,12 @@
    @Override
    public boolean doDie(L2Character killer)
    {
+      if (isNoblesseBlessed())
+      {
+         stopNoblesseBlessing(null);
+         storeEffect(true);
+      }
+      
       if (!super.doDie(killer))
          return false;
       if (this instanceof L2MerchantSummonInstance)
@@ -391,7 +403,8 @@
          else
             getOwner().setPetInvItems(false);
          
-         store();         
+         store();
+         storeEffect(true);
          owner.setPet(null);
          
          // Stop AI tasks
@@ -476,10 +489,22 @@
    {
    }
    
+   public void setRestoreSummon(boolean val)
+   {
+   }
+   
    public void store()
    {
    }
    
+   public void storeEffect(boolean storeEffects)
+   {
+   }
+   
+   public void restoreEffects()
+   {
+   }
+   
    @Override
    public L2ItemInstance getActiveWeaponInstance()
    {
Ultima modifica di Jumbo il mercoledì 11 maggio 2011, 10:19, modificato 1 volta in totale.
Jumbo
Si interessa
 
Messaggi: 60
Iscritto il: sabato 9 aprile 2011, 14:30

Prossimo

Torna a Lineage II Pubblica (Italian)

Chi c’è in linea

Visitano il forum: Nessuno e 2 ospiti