Skip to content

Commit

Permalink
Limit godstone activation evaluations
Browse files Browse the repository at this point in the history
Added a cooldown time for godstone evaluations to bring the actual activation rate closer to the template rate.
  • Loading branch information
neon-dev committed May 20, 2024
1 parent d17ae6e commit 47ec44f
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 97 deletions.
6 changes: 5 additions & 1 deletion game-server/config/main/custom.properties
Original file line number Diff line number Diff line change
Expand Up @@ -238,4 +238,8 @@ gameserver.pvpmap.random_boss.time = 0 30 14,18,21 ? * *
# Godstones:
# ----------------------------
# Default: 1.0
gameserver.rates.godstone.activation.rate = 1.0
gameserver.rates.godstone.activation.rate = 1.0

# Wait time in milliseconds between evaluations of a Godstone activation.
# Default: 500
gameserver.rates.godstone.evaluation.cooldown_millis = 500
11 changes: 5 additions & 6 deletions game-server/data/handlers/mysql5/MySQL5ItemStoneListDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;

import org.slf4j.Logger;
Expand Down Expand Up @@ -70,7 +66,10 @@ public void load(final Collection<Item> items) {
item.getItemStones().add(new ManaStone(item.getObjectId(), itemId, slot, PersistentState.UPDATED));
break;
case 1:
item.setGodStone(new GodStone(item, activatedCount, itemId, PersistentState.UPDATED));
item.addGodStone(itemId, activatedCount);
GodStone godstone = item.getGodStone();
if (godstone != null)
godstone.setPersistentState(PersistentState.UPDATED);
break;
case 2:
if (item.getSockets(true) <= item.getFusionStonesSize()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,7 @@ public class CustomConfig {

@Property(key = "gameserver.rates.godstone.activation.rate", defaultValue = "1.0")
public static float GODSTONE_ACTIVATION_RATE;

@Property(key = "gameserver.rates.godstone.evaluation.cooldown_millis", defaultValue = "500")
public static int GODSTONE_EVALUATION_COOLDOWN_MILLIS;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import com.aionemu.gameserver.ai.AISubState;
import com.aionemu.gameserver.ai.NpcAI;
import com.aionemu.gameserver.ai.event.AIEventType;
import com.aionemu.gameserver.configs.main.CustomConfig;
import com.aionemu.gameserver.controllers.attack.AttackResult;
import com.aionemu.gameserver.controllers.attack.AttackStatus;
import com.aionemu.gameserver.controllers.attack.AttackUtil;
Expand Down Expand Up @@ -178,30 +177,25 @@ public void onAddHate(Creature attacker, boolean isNewInAggroList) {
* Perform tasks when Creature was attacked
*/
public final void onAttack(Creature creature, int damage, AttackStatus attackStatus) {
onAttack(creature, 0, TYPE.REGULAR, damage, true, LOG.REGULAR, attackStatus, true, HopType.DAMAGE);
onAttack(creature, null, TYPE.REGULAR, damage, true, LOG.REGULAR, attackStatus, HopType.DAMAGE);
}

public final void onAttack(Creature creature, int damage, AttackStatus attackStatus, Effect criticalEffect) {
onAttack(creature, 0, TYPE.REGULAR, damage, true, LOG.REGULAR, attackStatus, true, HopType.DAMAGE, criticalEffect);
onAttack(creature, null, TYPE.REGULAR, damage, true, LOG.REGULAR, attackStatus, HopType.DAMAGE, criticalEffect);
}

public final void onAttack(Effect effect, TYPE type, int damage, boolean notifyAttack, LOG logId, HopType hopType) {
onAttack(effect.getEffector(), effect.getSkillId(), type, damage, notifyAttack, logId, effect.getAttackStatus(),
!effect.isPeriodic() && effect.getSkillTemplate().getActivationAttribute() != ActivationAttribute.PROVOKED, hopType);
if (type == TYPE.DELAYDAMAGE)
effect.broadcastHate();
onAttack(effect.getEffector(), effect, type, damage, notifyAttack, logId, effect.getAttackStatus(), hopType, null);
}

public void onAttack(Creature attacker, int skillId, TYPE type, int damage, boolean notifyAttack, LOG logId, AttackStatus status,
boolean allowGodstoneActivation, HopType hopType) {
onAttack(attacker, skillId, type, damage, notifyAttack, logId, status, allowGodstoneActivation, hopType, null);
public void onAttack(Creature attacker, Effect effect, TYPE type, int damage, boolean notifyAttack, LOG logId, AttackStatus status, HopType hopType) {
onAttack(attacker, effect, type, damage, notifyAttack, logId, status, hopType, null);
}

/**
* Perform tasks when Creature was attacked
*/
public void onAttack(Creature attacker, int skillId, TYPE type, int damage, boolean notifyAttack, LOG logId, AttackStatus status,
boolean allowGodstoneActivation, HopType hopType, Effect criticalEffect) {
private void onAttack(Creature attacker, Effect effect, TYPE type, int damage, boolean notifyAttack, LOG logId, AttackStatus status, HopType hopType, Effect criticalEffect) {
if (!getOwner().isSpawned())
return;
if (damage != 0 && notifyAttack) {
Expand All @@ -222,23 +216,25 @@ public void onAttack(Creature attacker, int skillId, TYPE type, int damage, bool
}
}
}
getOwner().getObserveController().notifyAttackedObservers(attacker, skillId);
getOwner().getObserveController().notifyAttackedObservers(attacker, effect == null ? 0 : effect.getSkillId());
}

getOwner().getAggroList().addDamage(attacker, damage, notifyAttack, hopType);

// notify all NPC's around that creature is attacking me
getOwner().getKnownList().forEachNpc(npc -> npc.getAi().onCreatureEvent(AIEventType.CREATURE_NEEDS_SUPPORT, getOwner()));
getOwner().getLifeStats().reduceHp(type, damage, skillId, logId, attacker, true);
getOwner().getLifeStats().reduceHp(type, damage, effect == null ? 0 : effect.getSkillId(), logId, attacker, true);
getOwner().incrementAttackedCount();

if (!getOwner().isDead() && attacker instanceof Player player) {
if (criticalEffect != null) {
criticalEffect.applyEffect();
}
if (allowGodstoneActivation && status != AttackStatus.DODGE && status != AttackStatus.RESIST)
if ((effect == null || effect.tryActivateGodstone()) && status != AttackStatus.DODGE && status != AttackStatus.RESIST)
calculateGodStoneEffects(player);
}
if (effect != null && type == TYPE.DELAYDAMAGE)
effect.broadcastHate();
}

private void calculateGodStoneEffects(Player attacker) {
Expand All @@ -251,36 +247,30 @@ private void applyGodStoneEffect(Player attacker, Item weapon, boolean isMainHan
if (weapon == null || !weapon.hasGodStone())
return;
GodStone godStone = weapon.getGodStone();
GodstoneInfo godStoneInfo = godStone.getGodstoneInfo();
if (godStoneInfo == null)
if (!godStone.tryActivate(isMainHandWeapon, getOwner()))
return;

int procProbability = isMainHandWeapon ? godStoneInfo.getProbability() : godStoneInfo.getProbabilityLeft();
procProbability *= CustomConfig.GODSTONE_ACTIVATION_RATE;
procProbability -= getOwner().getGameStats().getStat(StatEnum.PROC_REDUCE_RATE, 0).getCurrent();

if (Rnd.get(1, 1000) <= procProbability) {
ItemTemplate template = DataManager.ITEM_DATA.getItemTemplate(godStone.getItemId());
Skill skill = SkillEngine.getInstance().getSkill(attacker, godStoneInfo.getSkillId(), godStoneInfo.getSkillLevel(), getOwner(), template);
skill.setFirstTargetRangeCheck(false);
if (!skill.canUseSkill(CastState.CAST_START))
return;
Effect effect = new Effect(skill, getOwner());
effect.initialize();
effect.applyEffect();
PacketSendUtility.sendPacket(attacker, SM_SYSTEM_MESSAGE.STR_SKILL_PROC_EFFECT_OCCURRED(skill.getSkillTemplate().getL10n()));
// Illusion Godstones
if (godStoneInfo.getBreakProb() > 0) {
godStone.increaseActivatedCount();
if (godStone.getActivatedCount() > godStoneInfo.getNonBreakCount() && Rnd.get(1, 1000) <= godStoneInfo.getBreakProb()) {
// TODO: Delay 10 Minutes, send messages etc
// PacketSendUtility.sendPacket(owner, SM_SYSTEM_MESSAGE.STR_MSG_BREAK_PROC_REMAIN_START(equippedItem.getL10n(),
// itemTemplate.getL10nId()));
weapon.setGodStone(null);
PacketSendUtility.sendPacket(attacker,
SM_SYSTEM_MESSAGE.STR_MSG_BREAK_PROC(weapon.getL10n(), DataManager.ITEM_DATA.getItemTemplate(godStone.getItemId()).getL10n()));
ItemPacketService.updateItemAfterInfoChange(attacker, weapon);
}
GodstoneInfo godstoneInfo = godStone.getGodstoneInfo();
ItemTemplate template = DataManager.ITEM_DATA.getItemTemplate(godStone.getItemId());
Skill skill = SkillEngine.getInstance().getSkill(attacker, godstoneInfo.getSkillId(), godstoneInfo.getSkillLevel(), getOwner(), template);
skill.setFirstTargetRangeCheck(false);
if (!skill.canUseSkill(CastState.CAST_START))
return;
Effect effect = new Effect(skill, getOwner());
effect.initialize();
effect.applyEffect();
PacketSendUtility.sendPacket(attacker, SM_SYSTEM_MESSAGE.STR_SKILL_PROC_EFFECT_OCCURRED(skill.getSkillTemplate().getL10n()));
// Illusion Godstones
if (godstoneInfo.getBreakProb() > 0) {
godStone.increaseActivatedCount();
if (godStone.getActivatedCount() > godstoneInfo.getNonBreakCount() && Rnd.get(1, 1000) <= godstoneInfo.getBreakProb()) {
// TODO: Delay 10 Minutes, send messages etc
// PacketSendUtility.sendPacket(owner, SM_SYSTEM_MESSAGE.STR_MSG_BREAK_PROC_REMAIN_START(equippedItem.getL10n(),
// itemTemplate.getL10nId()));
weapon.setGodStone(null);
PacketSendUtility.sendPacket(attacker,
SM_SYSTEM_MESSAGE.STR_MSG_BREAK_PROC(weapon.getL10n(), DataManager.ITEM_DATA.getItemTemplate(godStone.getItemId()).getL10n()));
ItemPacketService.updateItemAfterInfoChange(attacker, weapon);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.aionemu.gameserver.services.drop.DropRegistrationService;
import com.aionemu.gameserver.services.drop.DropService;
import com.aionemu.gameserver.services.event.EventService;
import com.aionemu.gameserver.skillengine.model.Effect;
import com.aionemu.gameserver.skillengine.model.HopType;
import com.aionemu.gameserver.skillengine.model.SkillTemplate;
import com.aionemu.gameserver.taskmanager.tasks.MoveTaskManager;
Expand Down Expand Up @@ -288,8 +289,8 @@ public void onAddHate(Creature attacker, boolean isNewInAggroList) {
}

@Override
public void onAttack(Creature attacker, int skillId, TYPE type, int damage, boolean notifyAttack, LOG logId, AttackStatus attackStatus,
boolean allowGodstoneActivation, HopType hopType) {
public void onAttack(Creature attacker, Effect effect, TYPE type, int damage, boolean notifyAttack, LOG logId, AttackStatus attackStatus,
HopType hopType) {
if (getOwner().isDead())
return;
final Creature actingCreature;
Expand All @@ -300,7 +301,7 @@ public void onAttack(Creature attacker, int skillId, TYPE type, int damage, bool
else
actingCreature = attacker.getActingCreature();

super.onAttack(actingCreature, skillId, type, damage, notifyAttack, logId, attackStatus, allowGodstoneActivation, hopType);
super.onAttack(actingCreature, effect, type, damage, notifyAttack, logId, attackStatus, hopType);

Npc npc = getOwner();
ShoutEventHandler.onEnemyAttack((NpcAI) npc.getAi(), attacker);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,8 @@ public void attackTarget(Creature target, int time, boolean skipChecks) {
}

@Override
public void onAttack(Creature attacker, int skillId, TYPE type, int damage, boolean notifyAttack, LOG logId, AttackStatus attackStatus,
boolean allowGodstoneActivation, HopType hopType) {
public void onAttack(Creature attacker, Effect effect, TYPE type, int damage, boolean notifyAttack, LOG logId, AttackStatus attackStatus,
HopType hopType) {
if (getOwner().isDead())
return;

Expand All @@ -437,7 +437,7 @@ public void onAttack(Creature attacker, int skillId, TYPE type, int damage, bool

cancelUseItem();
cancelGathering();
super.onAttack(attacker, skillId, type, damage, notifyAttack, logId, attackStatus, allowGodstoneActivation, hopType);
super.onAttack(attacker, effect, type, damage, notifyAttack, logId, attackStatus, hopType);

if (attacker instanceof Npc) {
ShoutEventHandler.onAttack((NpcAI) attacker.getAi(), getOwner());
Expand All @@ -447,13 +447,6 @@ public void onAttack(Creature attacker, int skillId, TYPE type, int damage, bool
lastAttackedMillis = System.currentTimeMillis();
}

/**
* @param skillId
* @param targetType
* @param x
* @param y
* @param z
*/
public void useSkill(int skillId, int targetType, float x, float y, float z, int time) {
Player player = getOwner();

Expand All @@ -469,14 +462,6 @@ public void useSkill(int skillId, int targetType, float x, float y, float z, int
}
}

/**
* @param template
* @param targetType
* @param x
* @param y
* @param z
* @param clientHitTime
*/
public void useSkill(SkillTemplate template, int targetType, float x, float y, float z, int clientHitTime, int skillLevel) {
Player player = getOwner();
Skill skill = SkillEngine.getInstance().getSkillFor(player, template, player.getTarget());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.services.summons.SummonsService;
import com.aionemu.gameserver.skillengine.SkillEngine;
import com.aionemu.gameserver.skillengine.model.Effect;
import com.aionemu.gameserver.skillengine.model.HopType;
import com.aionemu.gameserver.skillengine.model.Skill;
import com.aionemu.gameserver.taskmanager.tasks.PlayerMoveTaskManager;
Expand Down Expand Up @@ -89,16 +90,16 @@ public void attackTarget(Creature target, int time, boolean skipChecks) {
}

@Override
public void onAttack(Creature creature, int skillId, TYPE type, int damage, boolean notifyAttack, LOG log, AttackStatus attackStatus,
boolean allowGodstoneActivation, HopType hopType) {
public void onAttack(Creature creature, Effect effect, TYPE type, int damage, boolean notifyAttack, LOG log, AttackStatus attackStatus,
HopType hopType) {
if (getOwner().isDead())
return;

// temp
if (getOwner().getMode() == SummonMode.RELEASE)
return;

super.onAttack(creature, skillId, type, damage, notifyAttack, log, attackStatus, allowGodstoneActivation, hopType);
super.onAttack(creature, effect, type, damage, notifyAttack, log, attackStatus, hopType);
PacketSendUtility.sendPacket(getOwner().getMaster(), new SM_SUMMON_UPDATE(getOwner()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public void checkShield(List<AttackResult> attackList, Effect attackerEffect, Cr
effect.endEffect(); // one skill reflection ends the shield effect
return;
} else { // apply reflect damage
attacker.getController().onAttack(effect.getEffected(), 0, TYPE.REGULAR, reflectedHit, false, LOG.REGULAR, null, false, null);
attacker.getController().onAttack(effect.getEffected(), effect, TYPE.REGULAR, reflectedHit, false, LOG.REGULAR, null, null);
}
}
break;
Expand All @@ -169,14 +169,14 @@ public void checkShield(List<AttackResult> attackList, Effect attackerEffect, Cr
effectorDamage = attackResult.getDamage();
} else
damageProtected = hit;
int finalDamage = attackResult.getDamage() - damageProtected;
attackResult.setDamage((finalDamage <= 0 ? 0 : finalDamage));
int finalDamage = Math.max(0, attackResult.getDamage() - damageProtected);
attackResult.setDamage(finalDamage);
attackResult.setShieldType(shieldType.getId());
attackResult.setProtectedSkillId(effect.getSkillId());
attackResult.setProtectedDamage(effectorDamage);
attackResult.setProtectorId(effect.getEffectorId());
effect.getEffector().getController().onAttack(attacker, effect.getSkillId(), TYPE.PROTECTDMG, effectorDamage, false, LOG.REGULAR,
attackResult.getAttackStatus(), attackerEffect != null ? attackerEffect.getSkillTemplate().getActivationAttribute() != ActivationAttribute.PROVOKED : true, null);
effect.getEffector().getController().onAttack(attacker, attackerEffect, TYPE.PROTECTDMG, effectorDamage, false, LOG.REGULAR,
attackResult.getAttackStatus(), null);
// dont launch subeffect if damage is fully absorbed
if (!isPunchShield(attackerEffect))
attackResult.setLaunchSubEffect(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.aionemu.gameserver.model.items.storage.StorageType;
import com.aionemu.gameserver.model.stats.calc.StatOwner;
import com.aionemu.gameserver.model.stats.calc.functions.StatFunction;
import com.aionemu.gameserver.model.templates.item.GodstoneInfo;
import com.aionemu.gameserver.model.templates.item.Improvement;
import com.aionemu.gameserver.model.templates.item.ItemTemplate;
import com.aionemu.gameserver.model.templates.item.ItemUseLimits;
Expand Down Expand Up @@ -463,24 +464,21 @@ public int getGodStoneId() {
return godStone == null ? 0 : godStone.getItemId();
}

/**
* @param itemId
* @return
*/
public void addGodStone(int itemId) {
addGodStone(itemId, 0);
}

public void addGodStone(int itemId, int activatedCount) {
GodstoneInfo godstoneInfo = DataManager.ITEM_DATA.getItemTemplate(itemId).getGodstoneInfo();
if (godstoneInfo == null) {
log.warn("Item " + itemId + " has no godstone info");
return;
}
if (godStone != null)
setGodStone(null);
godStone = new GodStone(this, activatedCount, itemId, PersistentState.NEW);
godStone = new GodStone(this, activatedCount, itemId, godstoneInfo, PersistentState.NEW);
}

/**
* @param godStone
* the goodStone to set
*/
public void setGodStone(GodStone godStone) {
if (godStone == null) {
this.godStone.setPersistentState(PersistentState.DELETED);
Expand Down
Loading

0 comments on commit 47ec44f

Please sign in to comment.