com.softwaremagico.tm.character.benefices.RandomBeneficeDefinition Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of think-machine-random Show documentation
Show all versions of think-machine-random Show documentation
Think Machine - A Fading Suns character generator (random character creation)
package com.softwaremagico.tm.character.benefices;
/*-
* #%L
* Think Machine (Core)
* %%
* Copyright (C) 2017 - 2018 Softwaremagico
* %%
* This software is designed by Jorge Hortelano Otero. Jorge Hortelano Otero
* Valencia (Spain).
*
* 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 2 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 .
* #L%
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import com.softwaremagico.tm.InvalidXmlElementException;
import com.softwaremagico.tm.character.CharacterPlayer;
import com.softwaremagico.tm.character.creation.CostCalculator;
import com.softwaremagico.tm.character.creation.FreeStyleCharacterCreation;
import com.softwaremagico.tm.log.RandomGenerationLog;
import com.softwaremagico.tm.random.RandomSelector;
import com.softwaremagico.tm.random.exceptions.ImpossibleToAssignMandatoryElementException;
import com.softwaremagico.tm.random.exceptions.InvalidRandomElementSelectedException;
import com.softwaremagico.tm.random.selectors.DifficultLevelPreferences;
import com.softwaremagico.tm.random.selectors.IGaussianDistribution;
import com.softwaremagico.tm.random.selectors.IRandomPreference;
import com.softwaremagico.tm.random.selectors.StatusPreferences;
import com.softwaremagico.tm.random.selectors.TraitCostPreferences;
public class RandomBeneficeDefinition extends RandomSelector {
private static final int MAX_AFFLICTIONS = 2;
private static final String CASH_BENEFICE_ID = "cash";
private static final String ESCAPED_PREFIX = "escaped";
public RandomBeneficeDefinition(CharacterPlayer characterPlayer, Set preferences)
throws InvalidXmlElementException {
this(characterPlayer, preferences, new HashSet(), new HashSet());
}
public RandomBeneficeDefinition(CharacterPlayer characterPlayer, Set preferences,
Set mandatoryBenefices, Set suggestedBenefices)
throws InvalidXmlElementException {
super(characterPlayer, null, preferences, mandatoryBenefices, suggestedBenefices);
}
@Override
public void assign() throws InvalidXmlElementException, InvalidRandomElementSelectedException {
// Later, the others.
while (CostCalculator.getBeneficesCosts(getCharacterPlayer()) < FreeStyleCharacterCreation
.getTraitsPoints(getCharacterPlayer().getInfo().getAge()) && !getWeightedElements().isEmpty()) {
// Select a benefice
final BeneficeDefinition selectedBenefice = selectElementByWeight();
assignBenefice(selectedBenefice,
FreeStyleCharacterCreation.getTraitsPoints(getCharacterPlayer().getInfo().getAge())
- CostCalculator.getBeneficesCosts(getCharacterPlayer()));
}
}
protected void assignBenefice(BeneficeDefinition selectedBenefice, int maxPoints)
throws InvalidXmlElementException {
// Select the range of the benefice.
final AvailableBenefice selectedBeneficeWithLevel = assignLevelOfBenefice(selectedBenefice, maxPoints);
if (selectedBeneficeWithLevel != null) {
// Only a few afflictions.
if (selectedBeneficeWithLevel.getBeneficeClassification() == BeneficeClassification.AFFLICTION) {
if (getCharacterPlayer().getAfflictions().size() < MAX_AFFLICTIONS) {
try {
getCharacterPlayer().addBenefice(selectedBeneficeWithLevel);
} catch (BeneficeAlreadyAddedException e) {
// Not add it again.
}
}
} else {
try {
getCharacterPlayer().addBenefice(selectedBeneficeWithLevel);
RandomGenerationLog.info(this.getClass().getName(),
"Added benefice '" + selectedBeneficeWithLevel + "'.");
} catch (BeneficeAlreadyAddedException e) {
// If level is bigger... replace it.
final AvailableBenefice originalBenefice = getCharacterPlayer()
.getBenefice(selectedBenefice.getId());
if (originalBenefice.getCost() < selectedBeneficeWithLevel.getCost()) {
getCharacterPlayer().removeBenefice(originalBenefice);
try {
getCharacterPlayer().addBenefice(selectedBeneficeWithLevel);
RandomGenerationLog.info(this.getClass().getName(), "Replacing benefice '"
+ originalBenefice + "' with '" + selectedBeneficeWithLevel + "'.");
} catch (BeneficeAlreadyAddedException e1) {
RandomGenerationLog.errorMessage(this.getClass().getName(), e1);
}
}
}
}
}
removeElementWeight(selectedBenefice);
// Only one fighting style by character.
if (selectedBenefice.getGroup().equals(BeneficeGroup.FIGHTING)) {
for (final BeneficeDefinition beneficeDefinition : BeneficeDefinitionFactory.getInstance()
.getBenefices(BeneficeGroup.FIGHTING, getCharacterPlayer().getLanguage(), getCharacterPlayer().getModuleName())) {
removeElementWeight(beneficeDefinition);
}
}
// Only one 'escaped' benefice
if (selectedBenefice.getId().startsWith(ESCAPED_PREFIX)) {
for (final BeneficeDefinition checkBenefice : getAllElements()) {
if (checkBenefice.getId().startsWith(ESCAPED_PREFIX)) {
removeElementWeight(checkBenefice);
}
}
}
}
@Override
protected Collection getAllElements() throws InvalidXmlElementException {
return BeneficeDefinitionFactory.getInstance().getElements(getCharacterPlayer().getLanguage(), getCharacterPlayer().getModuleName());
}
@Override
protected int getWeight(BeneficeDefinition benefice) throws InvalidRandomElementSelectedException {
// No restricted benefices.
if (benefice.getRestrictedFactionGroup() != null && getCharacterPlayer().getFaction() != null
&& benefice.getRestrictedFactionGroup() != getCharacterPlayer().getFaction().getFactionGroup()) {
throw new InvalidRandomElementSelectedException(
"Benefice '" + benefice + "' is restricted to '" + benefice.getRestrictedFactionGroup() + "'.");
}
// No special benefices
if (benefice.getGroup() == BeneficeGroup.RESTRICTED) {
throw new InvalidRandomElementSelectedException("Benefice '" + benefice + "' is restricted.");
}
// PNJs likes money changes.
if (benefice.getId().equalsIgnoreCase(CASH_BENEFICE_ID)) {
return GOOD_PROBABILITY;
}
// No faction preference selected. All benefices has the same
// probability.
return 1;
}
/**
* Returns a cost for a benefice depending on the preferences of the character.
*
* @param benefice
* @param maxPoints
* @return
* @throws InvalidXmlElementException
*/
private AvailableBenefice assignLevelOfBenefice(BeneficeDefinition benefice, int maxPoints)
throws InvalidXmlElementException {
IGaussianDistribution selectedTraitCost = TraitCostPreferences.getSelected(getPreferences());
if (benefice.getId().equalsIgnoreCase(CASH_BENEFICE_ID)) {
final DifficultLevelPreferences difficultPreferences = DifficultLevelPreferences
.getSelected(getPreferences());
switch (difficultPreferences) {
case EASY:
case VERY_EASY:
selectedTraitCost = TraitCostPreferences.LOW;
break;
case MEDIUM:
case HARD:
// Be careful. maxPoints can limit this value.
selectedTraitCost = TraitCostPreferences.GOOD;
break;
case VERY_HARD:
// Be careful. maxPoints can limit this value.
selectedTraitCost = TraitCostPreferences.VERY_HIGH;
break;
}
}
if (benefice.getGroup() != null && benefice.getGroup().equals(BeneficeGroup.STATUS)) {
// Status has also an special preference.
final IGaussianDistribution selectedStatus = StatusPreferences.getSelected(getPreferences());
if (selectedStatus != null) {
selectedTraitCost = selectedStatus;
}
}
int maxRangeSelected = selectedTraitCost.randomGaussian();
if (maxRangeSelected > maxPoints) {
maxRangeSelected = maxPoints;
}
RandomGenerationLog.info(this.getClass().getName(),
"MaxPoints of '" + benefice + "' are '" + maxRangeSelected + "'.");
Set beneficeLevels = AvailableBeneficeFactory.getInstance()
.getAvailableBeneficesByDefinition(getCharacterPlayer().getLanguage(), getCharacterPlayer().getModuleName(), benefice);
// Cannot be null, but...
if (beneficeLevels == null) {
beneficeLevels = new HashSet<>();
}
final List sortedBenefices = new ArrayList<>(beneficeLevels);
// Sort by cost (descending). Adding if a benefice has preferences
// (ascending).
Collections.sort(sortedBenefices, new Comparator() {
@Override
public int compare(AvailableBenefice o1, AvailableBenefice o2) {
final double o1Preferred = getRandomDefinitionBonus(o1.getRandomDefinition());
final double o2Preferred = getRandomDefinitionBonus(o2.getRandomDefinition());
if ((int) (o1Preferred - o2Preferred) != 0) {
return (int) (o1Preferred - o2Preferred);
}
return Integer.compare(o2.getCost(), o1.getCost());
}
});
RandomGenerationLog.info(this.getClass().getName(),
"Available benefice levels of '" + benefice + "' are '" + sortedBenefices + "'.");
for (final AvailableBenefice availableBenefice : sortedBenefices) {
try {
validateElement(availableBenefice.getRandomDefinition());
} catch (InvalidRandomElementSelectedException e) {
continue;
}
if (Math.abs(availableBenefice.getCost()) <= maxRangeSelected
// Or is mandatory and is the last of the list.
|| (isMandatory(availableBenefice.getBeneficeDefinition())
&& Objects.equals(availableBenefice, sortedBenefices.get(sortedBenefices.size() - 1)))) {
return availableBenefice;
}
}
return null;
}
@Override
protected void assignIfMandatory(BeneficeDefinition benefice)
throws InvalidXmlElementException, ImpossibleToAssignMandatoryElementException {
// Set status of the character.
try {
if ((benefice.getGroup() != null && benefice.getGroup().equals(BeneficeGroup.STATUS))
&& getWeight(benefice) > 0 && getCharacterPlayer().getFaction() != null
&& Objects.equals(benefice.getRestrictedFactionGroup(),
getCharacterPlayer().getFaction().getFactionGroup())) {
final IGaussianDistribution selectedStatus = StatusPreferences.getSelected(getPreferences());
if (selectedStatus != null) {
RandomGenerationLog.debug(this.getClass().getName(),
"Searching grade '" + selectedStatus.maximum() + "' of benefice '" + benefice + "'.");
assignBenefice(benefice, selectedStatus.maximum());
}
}
} catch (InvalidRandomElementSelectedException e) {
// Weight is zero. Do nothing.
}
}
@Override
protected void assignMandatoryValues(Set mandatoryValues) throws InvalidXmlElementException {
for (final BeneficeDefinition selectedBenefice : mandatoryValues) {
// Mandatory benefices can exceed the initial traits points.
assignBenefice(selectedBenefice,
FreeStyleCharacterCreation.getFreeAvailablePoints(getCharacterPlayer().getInfo().getAge()));
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy