Index: D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/L2Summon.java =================================================================== --- D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/L2Summon.java (revision 2173) +++ D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/L2Summon.java (working copy) @@ -196,6 +196,82 @@ public synchronized void doDie(L2Character killer) { + // if a pet is killed by a player or another player's pet/summon, + // treat as if the player killed the pet's owner, in terms of pvp + // flags, PK status and Karma. + // do NOT increase PvP or PK count when killing pets!!! + if (killer != null) + { + if ( !ZoneManager.getInstance().checkIfInZonePvP(this) ) + { + // if killed by a Summon, we should calculate with the owner PcInstance + if(killer instanceof L2Summon) + { + killer = ((L2Summon)killer).getOwner(); + } + if(getOwner().getClan()==null || + (killer instanceof L2PcInstance && ((L2PcInstance)killer).getClan()==null )|| + (killer instanceof L2PcInstance && !(((L2PcInstance)killer).getClan().isAtWarWith(getClanId()) ) && ((L2PcInstance)killer).getWantsPeace() == 0 && getWantsPeace() == 0)) + { + // karma gain/loss is only done outside of a pvpzone, BUT, items can still drop in one! + if ( killer.getObjectId() != this.getObjectId()) + { + // Calculate L2PcInstance attacker Karma increase + if (killer instanceof L2PcInstance ) + { + L2PcInstance pk = (L2PcInstance) killer; + + // Check if the L2PcInstance killed wasn't PvP Flagged + if (this.getPvpFlag() == 0 && this.getOwner().getPvpFlag() == 0 ) + { + // Check if the owner of this killed summon haven't Karma + if (this.getKarma() == 0 && this.getOwner().getKarma() == 0) + { + // Get attacker level and PK counter + int pkLVL = pk.getLevel(); + int pkPKCount = pk.getPkKills(); + + int targLVL = this.getLevel(); + int baseKarma = Config.KARMA_MIN_KARMA; + int newKarma = baseKarma; + int karmaLimit = Config.KARMA_MAX_KARMA; + + // Check if the attacker has a PK counter greater than 0 + double pkCountMulti = 0; + if ( pkPKCount > 0 ) + pkCountMulti = pkPKCount / 2.0; + else + pkCountMulti = 1; + if ( pkCountMulti < 1 ) pkCountMulti = 1; + + // Calculate the level difference Multiplier between attacker and killed L2PcInstance + double lvlDiffMulti = 0.0; + if ( pkLVL > targLVL ) + lvlDiffMulti = ((double)pkLVL) / targLVL; + else + lvlDiffMulti = 1.0; + if ( lvlDiffMulti < 1 ) lvlDiffMulti = 1.0; + + // Calculate the new Karma of the attacker : newKarma = baseKarma*pkCountMulti*lvlDiffMulti + newKarma = (int)(newKarma*pkCountMulti*lvlDiffMulti); + + // Make sure newKarma is less than karmaLimit and higher than baseKarma + if ( newKarma < baseKarma ) newKarma = baseKarma; + if ( newKarma > karmaLimit ) newKarma = karmaLimit; + + // Add karma to attacker and increase its PK counter + pk.increaseKarma(newKarma); + + // Send a Server->Client UserInfo packet to attacker with its Karma and PK Counter + pk.sendPacket(new UserInfo(pk)); + } + } + } + } + } + } + } + DecayTask.getInstance().addDecayTask(this); super.doDie(killer); } @@ -367,4 +443,51 @@ { super.useMagic(skill); } + + /** + * Reduce the current HP of the L2PcInstance.

+ * + * Actions :

+ *
  • Reduce the current HP of the L2PcInstance
  • + *
  • If necessary, stand up the L2PcInstance and PvP Flag the attacker
  • + *
  • Send a System Message to the L2PcInstance : S1_GAVE_YOU_S2_DMG


  • + * + * @param i The HP decrease value + * @param attacker The L2Character who attacks + * + */ + public void reduceCurrentHp(double i, L2Character attacker) + { + // Check if the L2Summon isn't Invulnerable + if (this.isInvul()) + return; + + //hotfix: Summons can not lose HP intown via PvP, unless the town is a PvP zone in config + //todo: Better fix is to ensure 100%that such inappropriate attacks are prevented altogether. + if (attacker != null && attacker != this && (attacker instanceof L2PcInstance || attacker instanceof L2Summon) + { + // Check if the attacked player is in a peace zone. + // only reds can be attacked in peace zones. + L2Zone zone = ZoneManager.getInstance().getZone(L2ZoneType.getZoneTypeName(L2ZoneType.ZoneType.Peace), getX(), getY()); //checking if char is in peace zone + if (zone != null && getKarma() == 0 ) + return; + + zone = ZoneManager.getInstance().getZone(L2ZoneType.getZoneTypeName(L2ZoneType.ZoneType.Town), getX(), getY()); //checking if char is in town zone + if (zone != null && getKarma() == 0 && Config.ZONE_TOWN == 0) + return; + } + + // Reduce the current HP of the L2PcInstance + super.reduceCurrentHp(i, attacker); + + // Check if the L2Summon isn't dead + if (!isDead()) + { + // Flag the attacker if it's a L2PcInstance outside a PvP area + if (attacker != null && attacker instanceof L2PcInstance) + ((L2PcInstance)attacker).checkPvP(this); + if (attacker != null && attacker instanceof L2Summon) + ((L2Summon)attacker).getOwner().checkPvP(this); + } + } } Index: D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/actor/pc/PcStat.java =================================================================== --- D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/actor/pc/PcStat.java (revision 2173) +++ D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/actor/pc/PcStat.java (working copy) @@ -37,7 +37,7 @@ int karmaRemove = value; karmaRemove /= Config.KARMA_XP_DIVIDER; - if (karmaRemove < 0) karmaRemove = 0; + if (karmaRemove <= 0) karmaRemove = 1; if (karmaRemove > getActiveChar().getKarma()) karmaRemove = getActiveChar().getKarma(); getActiveChar().setKarma(getActiveChar().getKarma() - karmaRemove); } Index: D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/L2PcInstance.java =================================================================== --- D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/L2PcInstance.java (revision 2173) +++ D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/L2PcInstance.java (working copy) @@ -2326,6 +2326,21 @@ // Check if the L2PcInstance isn't Invulnerable if (this.isInvul()) return; + + //hotfix: Players can not lose HP intown via PvP, unless the town is a PvP zone in config + //todo: Better fix is to ensure 100%that such inappropriate attacks are prevented altogether. + if (attacker != null && attacker != this && (attacker instanceof L2PcInstance || attacker instanceof L2Summon) + { + // Check if the attacked player is in a peace zone. + // only reds can be attacked in peace zones. + L2Zone zone = ZoneManager.getInstance().getZone(L2ZoneType.getZoneTypeName(L2ZoneType.ZoneType.Peace), getX(), getY()); //checking if char is in peace zone + if (zone != null && getKarma() == 0 ) + return; + + zone = ZoneManager.getInstance().getZone(L2ZoneType.getZoneTypeName(L2ZoneType.ZoneType.Town), getX(), getY()); //checking if char is in town zone + if (zone != null && getKarma() == 0 && Config.ZONE_TOWN == 0) + return; + } // Check and calculate transfered damage if (attacker != null && attacker != this) @@ -2400,16 +2415,17 @@ * */ public void doDie(L2Character killer) - { + { + int lostXP=0; //useful for new karma reduction...Team Olympus. // Reduce the Experience of the L2PcInstance in function of the calculated Death Penalty if (Config.ALT_GAME_DELEVEL) { if (!ZoneManager.getInstance().checkIfInZonePvP(this) && getSkillLevel(L2Skill.SKILL_LUCKY) < 0) if(killer != null && killer instanceof L2PcInstance && ((L2PcInstance)killer).getClan() != null && this.getClan() != null && this.getClan().isAtWarWith(((L2PcInstance)killer).getClanId())) - deathPenalty(true); + lostXP = deathPenalty(true); else - deathPenalty(false); + lostXP = deathPenalty(false); } @@ -2440,7 +2456,7 @@ if(getClan()==null ||(killer instanceof L2PcInstance && ((L2PcInstance)killer).getClan()==null )|| (killer instanceof L2PcInstance && !(((L2PcInstance)killer).getClan().isAtWarWith(getClanId()) ) && ((L2PcInstance)killer).getWantsPeace() == 0 && getWantsPeace() == 0)) { // karma gain/loss is only done outside of a pvpzone, BUT, items can still drop in one! - if ( killer.getObjectId() != this.getObjectId() ) + if ( killer.getObjectId() != this.getObjectId()) { // if killed by a Summon, we should calculate with the owner PcInstance if(killer instanceof L2Summon) @@ -2468,24 +2484,23 @@ int karmaLimit = Config.KARMA_MAX_KARMA; // Check if the attacker has a PK counter greater than 0 - int pkCountMulti = 0; + double pkCountMulti = 0; if ( pkPKCount > 0 ) - pkCountMulti = pkPKCount / 2; + pkCountMulti = pkPKCount / 2.0; else pkCountMulti = 1; if ( pkCountMulti < 1 ) pkCountMulti = 1; // Calculate the level difference Multiplier between attacker and killed L2PcInstance - int lvlDiffMulti = 0; + double lvlDiffMulti = 0.0; if ( pkLVL > targLVL ) - lvlDiffMulti = pkLVL / targLVL; + lvlDiffMulti = ((double)pkLVL) / targLVL; else - lvlDiffMulti = 1; - if ( lvlDiffMulti < 1 ) lvlDiffMulti = 1; + lvlDiffMulti = 1.0; + if ( lvlDiffMulti < 1 ) lvlDiffMulti = 1.0; // Calculate the new Karma of the attacker : newKarma = baseKarma*pkCountMulti*lvlDiffMulti - newKarma *= pkCountMulti; - newKarma *= lvlDiffMulti; + newKarma = (int)(newKarma*pkCountMulti*lvlDiffMulti); // Make sure newKarma is less than karmaLimit and higher than baseKarma if ( newKarma < baseKarma ) newKarma = baseKarma; @@ -2522,34 +2537,46 @@ pk.sendPacket(new UserInfo(pk)); } } + } - // KARMA LOSS FOR DEAD PLAYER - // when a PKer gets killed by another player or a L2MonsterInstance, it loseq a certain amount of Karma based on their level. - // this (with defaults) results in a level 1 losing about ~2 karma per death, and a lvl 70 loses about 11760 karma per death... - // You lose karma as long as you were not in a pvp zone and you did not kill urself. + //new karma loss code by team Olympus: + //Lose karma as a fraction of the XP you lost upon dying (ignoring how much + //of that XP might be returned by ressurection). + //NOTE: This also provides an elegant solution for no karma loss in PvP zones + //and for limitted karma loss in sieges (as specified in discussions from retail). if ( this.getKarma() > 0 ) { + // since the new formula is dependent on XP loss, leave the old formula + //effective when the server's options dictate no XP loss. + if (Config.ALT_GAME_DELEVEL) + { + int karmaLost = lostXP/260; //this 260 seems to work quite accurately. + if ( karmaLost <= 0 ) karmaLost = 1; + // Decrease Karma of the L2PcInstance and Send it a Server->Client StatusUpdate packet with Karma and PvP Flag if necessary + this.redreaseKarma(karmaLost); + } + else + { + // this formula seems to work relatively well: + // baseKarma * thisLVL * (thisLVL/100) + int finalKarma = 0; + double baseKarmaLost = Config.KARMA_LOST_BASE; + double karmaLost = baseKarmaLost; + double thisLVL = this.getLevel(); + double tempMulti = thisLVL / 100; - // this formula seems to work relatively well: - // baseKarma * thisLVL * (thisLVL/100) - int finalKarma = 0; - double baseKarmaLost = Config.KARMA_LOST_BASE; - double karmaLost = baseKarmaLost; - double thisLVL = this.getLevel(); - double tempMulti = thisLVL / 100; + // Calculate the new Karma of the attacker : newKarma = baseKarma*pkCountMulti*lvlDiffMulti + karmaLost *= thisLVL; // multiply by char lvl + karmaLost *= tempMulti; // divide by 0.charLVL + karmaLost = Math.round(karmaLost); + finalKarma = (int)karmaLost; + if ( finalKarma < 0 ) finalKarma = 1; - // Calculate the new Karma of the attacker : newKarma = baseKarma*pkCountMulti*lvlDiffMulti - karmaLost *= thisLVL; // multiply by char lvl - karmaLost *= tempMulti; // divide by 0.charLVL - karmaLost = Math.round(karmaLost); - finalKarma = (int)karmaLost; - if ( finalKarma < 0 ) finalKarma = 1; - - // Decrease Karma of the L2PcInstance and Send it a Server->Client StatusUpdate packet with Karma and PvP Flag if necessary - this.redreaseKarma(finalKarma); - + // Decrease Karma of the L2PcInstance and Send it a Server->Client StatusUpdate packet with Karma and PvP Flag if necessary + this.redreaseKarma(finalKarma); + } } } } @@ -2576,6 +2603,7 @@ Random rand = new Random(); boolean dropGM = Config.KARMA_DROP_GM; // do GMs drop gear or not? true = yes, false = no int dropPKLim = Config.KARMA_PK_LIMIT; // you do not drop items if you have less than dropPKLim PKs + int droptype = 0; if ( thisKarma > 0 && !(this.getPkKills() < dropPKLim && killer instanceof L2NpcInstance) && !ZoneManager.getInstance().checkIfInZonePvP(this)) { @@ -2583,7 +2611,7 @@ // Get drop settings //boolean gmStat = false; // keeps track of if player is a gm or not and if they are able to drop items int dropConstant = Config.KARMA_DROP_CONSTANT; // a constant used for drop chance calculation - //int dropLim = Config.KARMA_DROP_ITEM_LIMIT; // dropLim items dropped at most, equipped or unequipped doesnt matter. + int dropLim = Config.KARMA_DROP_ITEM_LIMIT; // dropLim items dropped at most, equipped or unequipped doesnt matter. //int randDropLim = Config.KARMA_RANDOM_DROP_LOCATION_LIMIT; // max amount of x/y units a dropped item may be placed double dropRate = Config.RATE_DROP_EQUIPMENT; // drop rate... double dropChanceINIT = Config.KARMA_DROPCHANCE_INITIAL_CHECK; // dropChanceINIT% drop chance, initial check @@ -2592,7 +2620,7 @@ double dropChanceUEQUIP = Config.KARMA_DROPCHANCE_UNEQUIPPED_ITEMS; // dropChanceUEQUIP% chance of dropping an equipped item, after initial check of dropChanceINIT - //if player hav karma and pkkils>4 and chance of drop 70% + //if player has karma and pkkils>4 and chance of drop 70% (using default settings) droppercent = (int)(dropChanceINIT + getKarma()/dropConstant*(100-dropChanceINIT)); droppercent *= dropRate; dropitems = (int)dropChanceUEQUIP; @@ -2600,106 +2628,124 @@ dropequipweap = (int)dropChanceEQUIP_WEAP; count = 0; while (!(isGM() && !dropGM) && - this.getPkKills() >= dropPKLim && rand.nextInt(100)0){ - int itemnrtodrop = rand.nextInt(count); - count = 0; - for (L2ItemInstance itemdrop : _inventory.getItems()){ - if (itemdrop.getItemId()!=57 && L2Item.TYPE2_QUEST != itemdrop.getItem().getType2() && - !noDropList.contains(itemdrop.getItemId()) && !petList.contains(itemdrop.getItemId())) - if ((!itemdrop.isEquipped() && droptype < dropitems) || - (itemdrop.isEquipped() && itemdrop.getItem().getType2() != L2Item.TYPE2_WEAPON && droptype < (dropitems + dropequip)) || - (itemdrop.isEquipped() && itemdrop.getItem().getType2() == L2Item.TYPE2_WEAPON && droptype >= (dropitems + dropequip))) - { - if (count == itemnrtodrop){ - if (itemdrop.isEquipped()) - this.getInventory().unEquipItemInSlotAndRecord(itemdrop.getEquipSlot()); - itemdrop = this.getInventory().dropItem(itemdrop,itemdrop.getCount()); - itemdrop.dropMe(this, this.getClientX(), this.getClientY(), this.getClientZ() + 20); - SystemMessage sm = new SystemMessage(298); - sm.addItemName(itemdrop.getItemId()); - this.sendPacket(sm); - InventoryUpdate iu = new InventoryUpdate(); // for inventory updating - iu.addRemovedItem(itemdrop); - this.sendPacket(iu); - _log.warning(getName()+" have karma and dropped id="+itemdrop.getItemId()+", count="+itemdrop.getCount()); - break; - } - count++; - } - } - } - droppercent /= 1.5; + droppercent /= 1.5; } } else if (!ZoneManager.getInstance().checkIfInZonePvP(this) || !isFestivalParticipant() ){ //if player haven't karma and lvl>4 and chance of drop 50% droppercent = Config.PLAYER_RATE_DROP; dropequip = Config.PLAYER_RATE_DROP_EQUIP; dropequipweap = Config.PLAYER_RATE_DROP_EQUIP_WEAPON; - dropitems = Config.PLAYER_RATE_DROP_ITEM; - count = 0; - while (!(isGM() && !dropGM) && killer instanceof L2NpcInstance - && getLevel()>4 && rand.nextInt(100)0){ - int itemnrtodrop = rand.nextInt(count); - count = 0; - for (L2ItemInstance itemdrop : _inventory.getItems()){ - if (itemdrop.getItemId()!=57 && L2Item.TYPE2_QUEST != itemdrop.getItem().getType2() && - !noDropList.contains(itemdrop.getItemId()) && !petList.contains(itemdrop.getItemId())) - if ((!itemdrop.isEquipped() && droptype < dropitems) || - (itemdrop.isEquipped() && itemdrop.getItem().getType2() != L2Item.TYPE2_WEAPON && droptype < (dropitems + dropequip)) || - (itemdrop.isEquipped() && itemdrop.getItem().getType2() == L2Item.TYPE2_WEAPON && droptype >= (dropitems + dropequip))) + if ((!itemdrop.isEquipped() && droptype == 3) || + (itemdrop.isEquipped() && itemdrop.getItem().getType2() != L2Item.TYPE2_WEAPON && droptype == 2) || + (itemdrop.isEquipped() && itemdrop.getItem().getType2() == L2Item.TYPE2_WEAPON && droptype == 1)) { - if (count == itemnrtodrop){ - if (itemdrop.isEquipped()) - this.getInventory().unEquipItemInSlotAndRecord(itemdrop.getEquipSlot()); - itemdrop = this.getInventory().dropItem(itemdrop,itemdrop.getCount()); - itemdrop.dropMe(this, this.getClientX(), this.getClientY(), this.getClientZ() + 20); - SystemMessage sm = new SystemMessage(298); - sm.addItemName(itemdrop.getItemId()); - this.sendPacket(sm); - InventoryUpdate iu = new InventoryUpdate(); // for inventory updating - iu.addRemovedItem(itemdrop); - this.sendPacket(iu); - _log.warning(getName()+" died and dropped id="+itemdrop.getItemId()+", count="+itemdrop.getCount()); - break; - } - count++; + if (itemdrop.isEquipped()) + this.getInventory().unEquipItemInSlotAndRecord(itemdrop.getEquipSlot()); + int quantity = rand.nextInt(itemdrop.getCount())+1; + itemdrop = this.getInventory().dropItem(itemdrop,quantity); + itemdrop.dropMe(this, this.getClientX(), this.getClientY(), this.getClientZ() + 20); + SystemMessage sm = new SystemMessage(298); + sm.addItemName(itemdrop.getItemId()); + this.sendPacket(sm); + InventoryUpdate iu = new InventoryUpdate(); // for inventory updating + iu.addRemovedItem(itemdrop); + this.sendPacket(iu); + _log.warning(getName()+" died and dropped id="+itemdrop.getItemId()+", count="+quantity); + itemFound = true; + break; } - } } - droppercent /= 5; - } - } + //if no item can be found for this droptype, try the next droptype + //(the next most rare type after the one originally selected - see comments above) + if (!itemFound) + droptype ++; + } + } } // Set the PvP Flag of the L2PcInstance @@ -2760,9 +2806,9 @@ *
  • Set the value of _expBeforeDeath
  • *
  • Set the new Experience value of the L2PcInstance and Decrease its level if necessary
  • *
  • Send a Server->Client StatusUpdate packet with its new Experience


  • - * + *
  • return the actual XP lost amount. */ - public void deathPenalty(boolean atwar) + public int deathPenalty(boolean atwar) { // TODO Need Correct Penalty @@ -2784,6 +2830,8 @@ // Set the new Experience value of the L2PcInstance getStat().addExp(-lostExp); + + return lostExp; } Index: D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/L2Character.java =================================================================== --- D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/L2Character.java (revision 2173) +++ D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/model/L2Character.java (working copy) @@ -4148,9 +4148,12 @@ player.setAttackingChar(this); player.setAttackingCharSkill(skill); - if(this instanceof L2PcInstance) + if(this instanceof L2PcInstance || this instanceof L2Summon) { - L2PcInstance activeChar = (L2PcInstance) this; + if (this instanceof L2PcInstance) + L2PcInstance activeChar = (L2PcInstance) this; + else //if (this instanceof L2Summon) + L2PcInstance activeChar = (L2PcInstance) this.getOwner(); // Check for PvP Flagging / Drawing Aggro if (skill.isOffensive()) Index: D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/skills/Formulas.java =================================================================== --- D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/skills/Formulas.java (revision 2173) +++ D:/Source/trunk/L2_Gameserver/java/net/sf/l2j/gameserver/skills/Formulas.java (working copy) @@ -1139,14 +1139,19 @@ { case STUN: // For normal Stun Attack, with skillType = STUN - pAtk = player.getPAtk(target); - pDef = target.getPDef(player); - pDef = target.calcStat(Stats.STUN_RES,pDef,target,null); - value = 30 * 100 + (int)(70 * 100 * ((float)skill.getLevel()/maxLevel)); - if (pDef > 0 && pAtk > 0) - value *= 0.6 * pAtk/pDef; - modifier = 100 * target.getCON()/30; - break; + int basechance = 50; + int perLevelBonus = 1; + if (skill.getId() == 92) //Shield stun is stronger (only pure stun skill) + { + basechance = 80; + perLevelBonus = 2; + } + pDef = target.calcStat(Stats.STUN_RES,0,target,null); + value = 750 * (basechance + perLevelBonus * skill.getLevel()); + modifier = target.getLevel()*(target.getCON() + pDef); + // CHANCE to stun gets no modifier from shots, whatsoever. + //stun+damage skills get a modifier in the damage part ONLY. + ssmodifier = 1; case CONFUSION: case MUTE: case PARALYZE: @@ -1178,18 +1183,17 @@ modifier = 100 * target.getDEX()/30; break; default: - // For normal Stun attack with skillType = PDAM - pAtk = (int)skill.getPower(); - pDef = target.getPDef(player); - pDef = target.calcStat(Stats.STUN_RES,pDef,target,null); -// value = 30 * 100 + (int)(70 * 100 * ((float)skill.getLevel()/maxLevel)); - value = 100 * 100; - if (pDef > 0 && pAtk > 0) - value *= 0.6 * pAtk/pDef; - modifier = 100 * target.getCON()/30; - break; + basechance = 50; + perLevelBonus = 1; + pDef = target.calcStat(Stats.STUN_RES,0,target,null); + value = 750 * (basechance + perLevelBonus * skill.getLevel()); + modifier = target.getLevel()*(target.getCON() + pDef); + //CHANCE to stun gets no modifier from shots, whatsoever. + //stun+damage skills get a modifier in the damage part ONLY. + ssmodifier = 1; + break; } - + if (modifier == 0) { _log.warning("Name: "+target.getName()+" has bad base stat value. Fix datapack or notify dp ppl");