|
|
|
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
|
|
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
|
|
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
|
|
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
|
|
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
|
|
|
// Magicbane Emulator Project © 2013 - 2022
|
|
|
|
// www.magicbane.com
|
|
|
|
|
|
|
|
|
|
|
|
package engine.objects;
|
|
|
|
|
|
|
|
import engine.gameManager.DbManager;
|
|
|
|
import engine.gameManager.PowersManager;
|
|
|
|
import engine.mbEnums;
|
|
|
|
import engine.net.ByteBufferWriter;
|
|
|
|
import engine.net.client.msg.ErrorPopupMsg;
|
|
|
|
import engine.powers.PowersBase;
|
|
|
|
import engine.server.MBServerStatics;
|
|
|
|
import org.pmw.tinylog.Logger;
|
|
|
|
|
|
|
|
import java.sql.ResultSet;
|
|
|
|
import java.sql.SQLException;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
|
|
|
|
|
|
|
public class CharacterPower extends AbstractGameObject {
|
|
|
|
|
|
|
|
private final PowersBase power;
|
|
|
|
private AtomicInteger trains = new AtomicInteger();
|
|
|
|
private short grantedTrains;
|
|
|
|
private int ownerUID;
|
|
|
|
private boolean trained = false;
|
|
|
|
private int requiredLevel = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* No Table ID Constructor
|
|
|
|
*/
|
|
|
|
public CharacterPower(PowersBase power, PlayerCharacter pc) {
|
|
|
|
super();
|
|
|
|
this.power = power;
|
|
|
|
this.trains.set(0);
|
|
|
|
this.grantedTrains = this.grantedTrains;
|
|
|
|
this.ownerUID = pc.getObjectUUID();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Normal Constructor
|
|
|
|
*/
|
|
|
|
public CharacterPower(PowersBase power, PlayerCharacter pc, int newUUID) {
|
|
|
|
super(newUUID);
|
|
|
|
this.power = power;
|
|
|
|
this.trains.set(0);
|
|
|
|
this.grantedTrains = this.grantedTrains;
|
|
|
|
this.ownerUID = pc.getObjectUUID();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ResultSet Constructor
|
|
|
|
*/
|
|
|
|
public CharacterPower(ResultSet rs, PlayerCharacter pc) throws SQLException {
|
|
|
|
super(rs);
|
|
|
|
int powersBaseToken = rs.getInt("PowersBaseToken");
|
|
|
|
this.power = PowersManager.getPowerByToken(powersBaseToken);
|
|
|
|
|
|
|
|
if (this.power != null && this.power.isWeaponPower())
|
|
|
|
this.trains.set(0);
|
|
|
|
else
|
|
|
|
this.trains.set(rs.getInt("trains"));
|
|
|
|
this.grantedTrains = this.grantedTrains;
|
|
|
|
this.ownerUID = pc.getObjectUUID();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public CharacterPower(ResultSet rs) throws SQLException {
|
|
|
|
super(rs);
|
|
|
|
int powersBaseToken = rs.getInt("PowersBaseToken");
|
|
|
|
this.power = PowersManager.getPowerByToken(powersBaseToken);
|
|
|
|
this.trains.set(rs.getInt("trains"));
|
|
|
|
this.grantedTrains = this.grantedTrains;
|
|
|
|
this.ownerUID = rs.getInt("CharacterID");
|
|
|
|
|
|
|
|
// this.owner = DbManager.PlayerCharacterQueries.GET_PLAYER_CHARACTER(rs.getInt("CharacterID"));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static PlayerCharacter getOwner(CharacterPower cp) {
|
|
|
|
return PlayerCharacter.getFromCache(cp.ownerUID);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This iterates through players runes and adds and removes powers as needed
|
|
|
|
* Don't Call this directly. Instead call pc.calculateSkills().
|
|
|
|
*/
|
|
|
|
public static void calculatePowers(AbstractCharacter absChar) {
|
|
|
|
if (absChar == null || absChar.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) == false)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PlayerCharacter pc = (PlayerCharacter) absChar;
|
|
|
|
// First add powers that don't exist
|
|
|
|
ConcurrentHashMap<Integer, CharacterPower> powers = pc.getPowers();
|
|
|
|
// ArrayList<PowerReq> genericPowers = PowerReq.getPowerReqsForAll();
|
|
|
|
// CharacterPower.grantPowers(genericPowers, powers, pc);
|
|
|
|
Race race = pc.race;
|
|
|
|
if (race != null) {
|
|
|
|
CharacterPower.grantPowers(race.getPowersGranted(), powers, pc);
|
|
|
|
} else
|
|
|
|
Logger.error("Failed to find Race for player " + pc.getObjectUUID());
|
|
|
|
BaseClass bc = pc.baseClass;
|
|
|
|
if (bc != null) {
|
|
|
|
CharacterPower.grantPowers(bc.getPowersGranted(), powers, pc);
|
|
|
|
} else
|
|
|
|
Logger.error("Failed to find BaseClass for player " + pc.getObjectUUID());
|
|
|
|
PromotionClass promo = pc.promotionClass;
|
|
|
|
if (promo != null)
|
|
|
|
CharacterPower.grantPowers(promo.getPowersGranted(), powers, pc);
|
|
|
|
ArrayList<CharacterRune> runes = pc.runes;
|
|
|
|
if (runes != null) {
|
|
|
|
for (CharacterRune rune : runes) {
|
|
|
|
CharacterPower.grantPowers(rune.getPowersGranted(), powers, pc);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
Logger.error("Failed to find Runes list for player " + pc.getObjectUUID());
|
|
|
|
|
|
|
|
// next remove any skills that no longer belong
|
|
|
|
Iterator<Integer> it = powers.keySet().iterator();
|
|
|
|
while (it.hasNext()) {
|
|
|
|
Integer token = it.next();
|
|
|
|
boolean valid = false;
|
|
|
|
// if (CharacterPower.powerAllowed(token, genericPowers, pc))
|
|
|
|
// continue;
|
|
|
|
if (CharacterPower.powerAllowed(token, race.getPowersGranted(), pc))
|
|
|
|
continue;
|
|
|
|
if (CharacterPower.powerAllowed(token, bc.getPowersGranted(), pc))
|
|
|
|
continue;
|
|
|
|
if (promo != null)
|
|
|
|
if (CharacterPower.powerAllowed(token, promo.getPowersGranted(), pc))
|
|
|
|
continue;
|
|
|
|
for (CharacterRune rune : runes) {
|
|
|
|
if (CharacterPower.powerAllowed(token, rune.getPowersGranted(), pc)) {
|
|
|
|
valid = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if power doesn't belong to any runes or skill, then remove it
|
|
|
|
if (!valid) {
|
|
|
|
CharacterPower cp = powers.get(token);
|
|
|
|
DbManager.CharacterPowerQueries.DELETE_CHARACTER_POWER(cp.getObjectUUID());
|
|
|
|
it.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This grants powers for specific runes
|
|
|
|
*/
|
|
|
|
private static void grantPowers(ArrayList<PowerReq> powersGranted, ConcurrentHashMap<Integer, CharacterPower> powers, PlayerCharacter pc) {
|
|
|
|
ConcurrentHashMap<String, CharacterSkill> skills = pc.getSkills();
|
|
|
|
|
|
|
|
for (PowerReq powerreq : powersGranted) {
|
|
|
|
PowersBase powersBase = powerreq.getPowersBase();
|
|
|
|
|
|
|
|
if (powersBase == null)
|
|
|
|
continue;
|
|
|
|
// skip if player already has power
|
|
|
|
if (powers.containsKey(powerreq.getToken())) {
|
|
|
|
CharacterPower cp = powers.get(powersBase.getToken());
|
|
|
|
if (cp != null)
|
|
|
|
if (cp.requiredLevel == 0) {
|
|
|
|
cp.requiredLevel = (int) powerreq.getLevel();
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If player not high enough level for power, then skip
|
|
|
|
if (pc.getLevel() < powerreq.getLevel())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// See if any prereq powers needed
|
|
|
|
boolean valid = true;
|
|
|
|
ConcurrentHashMap<Integer, Byte> preqs = powerreq.getPowerReqs();
|
|
|
|
for (Integer tok : preqs.keySet()) {
|
|
|
|
if (!powers.containsKey(tok))
|
|
|
|
valid = false;
|
|
|
|
else {
|
|
|
|
CharacterPower cpp = powers.get(tok);
|
|
|
|
if ((cpp.getTrains() + cpp.grantedTrains) < preqs.get(tok))
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!valid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// See if any prereq skills needed
|
|
|
|
preqs = powerreq.getSkillReqs();
|
|
|
|
for (Integer tok : preqs.keySet()) {
|
|
|
|
if (tok == 0)
|
|
|
|
continue;
|
|
|
|
CharacterSkill found = null;
|
|
|
|
for (CharacterSkill sk : skills.values()) {
|
|
|
|
if (sk.getToken() == tok) {
|
|
|
|
found = sk;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found != null) {
|
|
|
|
if (found.getModifiedAmountBeforeMods() < preqs.get(tok))
|
|
|
|
valid = false;
|
|
|
|
} else
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
if (!valid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (!powers.containsKey(powersBase.getToken())) {
|
|
|
|
CharacterPower newPower = new CharacterPower(powersBase, pc);
|
|
|
|
CharacterPower cp = null;
|
|
|
|
try {
|
|
|
|
cp = DbManager.CharacterPowerQueries.ADD_CHARACTER_POWER(newPower);
|
|
|
|
} catch (Exception e) {
|
|
|
|
cp = null;
|
|
|
|
}
|
|
|
|
if (cp != null) {
|
|
|
|
cp.requiredLevel = (int) powerreq.getLevel();
|
|
|
|
powers.put(powersBase.getToken(), cp);
|
|
|
|
} else
|
|
|
|
Logger.error("Failed to add CharacterPower to player " + pc.getObjectUUID());
|
|
|
|
} else {
|
|
|
|
CharacterPower cp = powers.get(powersBase.getToken());
|
|
|
|
if (cp != null)
|
|
|
|
if (cp.requiredLevel == 0) {
|
|
|
|
cp.requiredLevel = (int) powerreq.getLevel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void grantTrains(AbstractCharacter absChar) {
|
|
|
|
if (absChar == null || absChar.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter) == false)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PlayerCharacter pc = (PlayerCharacter) absChar;
|
|
|
|
ConcurrentHashMap<Integer, CharacterPower> powers = pc.getPowers();
|
|
|
|
for (CharacterPower cp : powers.values()) {
|
|
|
|
cp.grantedTrains = cp.getGrantedTrains(pc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This verifies if a power is valid for a players rune
|
|
|
|
*/
|
|
|
|
private static boolean powerAllowed(Integer token, ArrayList<PowerReq> powersGranted, PlayerCharacter pc) {
|
|
|
|
ConcurrentHashMap<String, CharacterSkill> skills = pc.getSkills();
|
|
|
|
ConcurrentHashMap<Integer, CharacterPower> powers = pc.getPowers();
|
|
|
|
if (skills == null || powers == null)
|
|
|
|
return false;
|
|
|
|
for (PowerReq powerreq : powersGranted) {
|
|
|
|
PowersBase pb = powerreq.getPowersBase();
|
|
|
|
if (pb != null) {
|
|
|
|
if (pb.getToken() == token) {
|
|
|
|
|
|
|
|
//test level requirements
|
|
|
|
if (powerreq.getLevel() > pc.getLevel()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//test skill requirements are met
|
|
|
|
ConcurrentHashMap<Integer, Byte> skillReqs = powerreq.getSkillReqs();
|
|
|
|
for (int tok : skillReqs.keySet()) {
|
|
|
|
boolean valid = false;
|
|
|
|
if (tok == 0)
|
|
|
|
continue;
|
|
|
|
for (CharacterSkill skill : skills.values()) {
|
|
|
|
if (skill.getToken() == tok) {
|
|
|
|
if (skill.getModifiedAmountBeforeMods() < skillReqs.get(tok))
|
|
|
|
return false;
|
|
|
|
valid = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!valid)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//test power prerequisites are met
|
|
|
|
ConcurrentHashMap<Integer, Byte> powerReqs = powerreq.getPowerReqs();
|
|
|
|
for (int tok : powerReqs.keySet()) {
|
|
|
|
if (!powers.containsKey(tok))
|
|
|
|
return false;
|
|
|
|
CharacterPower cp = powers.get(tok);
|
|
|
|
if (cp.getTotalTrains() < powerReqs.get(tok))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//everything passed. power is valid
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void serializeForClientMsg(CharacterPower characterPower, ByteBufferWriter writer) {
|
|
|
|
if (characterPower.power != null)
|
|
|
|
writer.putInt(characterPower.power.getToken());
|
|
|
|
else
|
|
|
|
writer.putInt(0);
|
|
|
|
writer.putInt(characterPower.getTrains());
|
|
|
|
}
|
|
|
|
|
|
|
|
public static CharacterPower getPower(int tableId) {
|
|
|
|
return DbManager.CharacterPowerQueries.GET_CHARACTER_POWER(tableId);
|
|
|
|
}
|
|
|
|
|
|
|
|
private short getGrantedTrains(PlayerCharacter pc) {
|
|
|
|
if (this.power != null && pc != null) {
|
|
|
|
// if (this.power.isWeaponPower()) {
|
|
|
|
// SkillsBase sb = null;
|
|
|
|
// try {
|
|
|
|
// sb = SkillsBase.getSkillsBaseByName(this.power.getSkillName());
|
|
|
|
// } catch (SQLException e) {}
|
|
|
|
// if (sb != null) {
|
|
|
|
// return pc.getBonuses().getByte("gt." + sb.getToken());
|
|
|
|
// } else
|
|
|
|
// return pc.getBonuses().getByte("gt." + this.power.getToken());
|
|
|
|
// } else
|
|
|
|
// return pc.getBonuses().getByte("gt." + this.power.getToken());
|
|
|
|
return PowerGrant.getGrantedTrains(this.power.getToken(), pc);
|
|
|
|
} else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Getters
|
|
|
|
*/
|
|
|
|
public PowersBase getPower() {
|
|
|
|
return power;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getPowerID() {
|
|
|
|
return power.getUUID();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isTrained() {
|
|
|
|
return trained;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setTrained(boolean b) {
|
|
|
|
trained = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getTrains() {
|
|
|
|
return this.trains.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Utils
|
|
|
|
*/
|
|
|
|
|
|
|
|
public short getGrantedTrains() {
|
|
|
|
return this.grantedTrains;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getTotalTrains() {
|
|
|
|
return (this.trains.get() + this.grantedTrains);
|
|
|
|
}
|
|
|
|
|
|
|
|
public float getTrainingCost(PlayerCharacter pc, NPC trainer) {
|
|
|
|
int charLevel = pc.getLevel();
|
|
|
|
int skillRank = this.trains.get() - 1 + this.requiredLevel;
|
|
|
|
|
|
|
|
|
|
|
|
float baseCost = 50 * this.requiredLevel; //TODO GET BASE COSTS OF SKILLS.
|
|
|
|
|
|
|
|
|
|
|
|
float sellPercent = -4f; //NOT SELL PERCENT!
|
|
|
|
float cost;
|
|
|
|
float const5;
|
|
|
|
int const2 = 1;
|
|
|
|
float const3 = 50;
|
|
|
|
float const4 = const3 + const2;
|
|
|
|
if (charLevel > 50)
|
|
|
|
const5 = 50 / const4;
|
|
|
|
else
|
|
|
|
const5 = charLevel / const4;
|
|
|
|
|
|
|
|
const5 = 1 - const5;
|
|
|
|
const5 = (float) (Math.log(const5) / Math.log(2) * .75f);
|
|
|
|
float rounded5 = Math.round(const5);
|
|
|
|
const5 = rounded5 - const5;
|
|
|
|
|
|
|
|
const5 *= -1;
|
|
|
|
|
|
|
|
const5 = (float) (Math.pow(2, const5) - 1);
|
|
|
|
|
|
|
|
const5 += 1;
|
|
|
|
const5 = Math.scalb(const5, (int) rounded5);
|
|
|
|
const5 *= (charLevel - skillRank);
|
|
|
|
const5 *= sellPercent;
|
|
|
|
|
|
|
|
const5 = (float) (Math.log(const5) / Math.log(2) * 3);
|
|
|
|
rounded5 = Math.round(const5);
|
|
|
|
const5 = rounded5 - const5;
|
|
|
|
const5 *= -1;
|
|
|
|
const5 = (float) (Math.pow(2, const5) - 1);
|
|
|
|
const5 += 1;
|
|
|
|
|
|
|
|
|
|
|
|
const5 = Math.scalb(const5, (int) rounded5);
|
|
|
|
const5 += 1;
|
|
|
|
cost = const5 * baseCost;
|
|
|
|
|
|
|
|
|
|
|
|
if (Float.isNaN(cost))
|
|
|
|
cost = baseCost;
|
|
|
|
return cost;
|
|
|
|
}
|
|
|
|
|
|
|
|
public synchronized boolean train(PlayerCharacter pc) {
|
|
|
|
if (pc == null || this.power == null)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
//see if any prereqs to train this power is met
|
|
|
|
if (!canTrain(pc))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
boolean succeeded = true;
|
|
|
|
int oldTrains = this.trains.get();
|
|
|
|
int tr = oldTrains + this.grantedTrains;
|
|
|
|
if (pc.getTrainsAvailable() <= 0)
|
|
|
|
return false;
|
|
|
|
if (tr == this.power.getMaxTrains()) //at max, stop here
|
|
|
|
return false;
|
|
|
|
else if (tr > this.power.getMaxTrains()) //catch incase we somehow go over
|
|
|
|
this.trains.set((this.power.getMaxTrains() - this.grantedTrains));
|
|
|
|
else //add the train
|
|
|
|
succeeded = this.trains.compareAndSet(oldTrains, oldTrains + 1);
|
|
|
|
|
|
|
|
if (this.trains.get() > this.power.getMaxTrains()) { //double check not over max trains
|
|
|
|
this.trains.set(this.power.getMaxTrains());
|
|
|
|
succeeded = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (succeeded) {
|
|
|
|
this.trained = true;
|
|
|
|
|
|
|
|
//update database
|
|
|
|
pc.addDatabaseJob("Skills", MBServerStatics.THIRTY_SECONDS);
|
|
|
|
|
|
|
|
//subtract from trains available
|
|
|
|
pc.modifyTrainsAvailable(-1);
|
|
|
|
|
|
|
|
pc.calculateSkills();
|
|
|
|
return true;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean reset(PlayerCharacter pc) {
|
|
|
|
if (pc == null || this.power == null)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
//see if any prereqs to refine this power is met
|
|
|
|
|
|
|
|
boolean succeeded = true;
|
|
|
|
int oldTrains = this.trains.get();
|
|
|
|
int tr = oldTrains + this.grantedTrains;
|
|
|
|
if (oldTrains < 1)
|
|
|
|
return false;
|
|
|
|
else //subtract the train
|
|
|
|
succeeded = this.trains.compareAndSet(oldTrains, 0);
|
|
|
|
if (succeeded) {
|
|
|
|
this.trained = true;
|
|
|
|
|
|
|
|
//update database
|
|
|
|
pc.addDatabaseJob("Skills", MBServerStatics.THIRTY_SECONDS);
|
|
|
|
|
|
|
|
//subtract from trains available
|
|
|
|
pc.modifyTrainsAvailable(oldTrains);
|
|
|
|
|
|
|
|
pc.calculateSkills();
|
|
|
|
return true;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean refine(PlayerCharacter pc) {
|
|
|
|
if (pc == null || this.power == null)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
//see if any prereqs to refine this power is met
|
|
|
|
if (!canRefine(pc))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
boolean succeeded = true;
|
|
|
|
int oldTrains = this.trains.get();
|
|
|
|
int tr = oldTrains + this.grantedTrains;
|
|
|
|
if (oldTrains < 1)
|
|
|
|
return false;
|
|
|
|
else //subtract the train
|
|
|
|
succeeded = this.trains.compareAndSet(oldTrains, oldTrains - 1);
|
|
|
|
if (succeeded) {
|
|
|
|
this.trained = true;
|
|
|
|
|
|
|
|
//update database
|
|
|
|
pc.addDatabaseJob("Skills", MBServerStatics.THIRTY_SECONDS);
|
|
|
|
|
|
|
|
//subtract from trains available
|
|
|
|
pc.modifyTrainsAvailable(1);
|
|
|
|
|
|
|
|
pc.calculateSkills();
|
|
|
|
return true;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//This verifies the power is not blocked from refining by prereqs on other powers.
|
|
|
|
private boolean canRefine(PlayerCharacter pc) {
|
|
|
|
if (this.power == null || pc == null)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ConcurrentHashMap<Integer, CharacterPower> powers = pc.getPowers();
|
|
|
|
Race race = pc.race;
|
|
|
|
if (race != null) {
|
|
|
|
if (!canRefine(race.getPowersGranted(), powers, pc))
|
|
|
|
return false;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
BaseClass bc = pc.baseClass;
|
|
|
|
if (bc != null) {
|
|
|
|
if (!canRefine(bc.getPowersGranted(), powers, pc))
|
|
|
|
return false;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
PromotionClass promo = pc.getPromotionClass();
|
|
|
|
if (promo != null)
|
|
|
|
if (!canRefine(promo.getPowersGranted(), powers, pc))
|
|
|
|
return false;
|
|
|
|
ArrayList<CharacterRune> runes = pc.getRunes();
|
|
|
|
if (runes != null) {
|
|
|
|
for (CharacterRune rune : runes) {
|
|
|
|
if (!canRefine(rune.getPowersGranted(), powers, pc))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//all tests passed. Can refine
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Serializing
|
|
|
|
*/
|
|
|
|
|
|
|
|
private boolean canRefine(ArrayList<PowerReq> powersGranted, ConcurrentHashMap<Integer, CharacterPower> powers, PlayerCharacter pc) {
|
|
|
|
for (PowerReq pr : powersGranted) {
|
|
|
|
ConcurrentHashMap<Integer, Byte> powerReqs = pr.getPowerReqs();
|
|
|
|
for (int token : powerReqs.keySet()) {
|
|
|
|
if (token == this.power.getToken()) {
|
|
|
|
//this is a prereq, find the power and make sure it has enough trains
|
|
|
|
int trainsReq = (int) powerReqs.get(token);
|
|
|
|
for (CharacterPower cp : powers.values()) {
|
|
|
|
if (cp.power.getToken() == pr.getToken()) {
|
|
|
|
if (this.getTotalTrains() <= trainsReq && cp.getTrains() > 0) {
|
|
|
|
ErrorPopupMsg.sendErrorMsg(pc, "You must refine " + cp.power.getName() + " to 0 before refining any more from this power.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean canTrain(PlayerCharacter pc) {
|
|
|
|
if (this.power == null || pc == null)
|
|
|
|
return false;
|
|
|
|
int token = this.power.getToken();
|
|
|
|
boolean valid = false;
|
|
|
|
Race race = pc.race;
|
|
|
|
if (race != null) {
|
|
|
|
if (CharacterPower.powerAllowed(token, race.getPowersGranted(), pc))
|
|
|
|
return true;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
BaseClass bc = pc.baseClass;
|
|
|
|
if (bc != null) {
|
|
|
|
if (CharacterPower.powerAllowed(token, bc.getPowersGranted(), pc))
|
|
|
|
return true;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
PromotionClass promo = pc.getPromotionClass();
|
|
|
|
if (promo != null)
|
|
|
|
if (CharacterPower.powerAllowed(token, promo.getPowersGranted(), pc))
|
|
|
|
return true;
|
|
|
|
ArrayList<CharacterRune> runes = pc.getRunes();
|
|
|
|
for (CharacterRune rune : runes)
|
|
|
|
if (CharacterPower.powerAllowed(token, rune.getPowersGranted(), pc))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void updateDatabase() {
|
|
|
|
DbManager.CharacterPowerQueries.updateDatabase(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getRequiredLevel() {
|
|
|
|
return requiredLevel;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setRequiredLevel(int requiredLevel) {
|
|
|
|
this.requiredLevel = requiredLevel;
|
|
|
|
}
|
|
|
|
}
|