com.softwaremagico.tm.character.occultism.RandomPsiquePath 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.occultism;
/*-
* #%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.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.CombatPreferences;
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.PsiqueLevelPreferences;
import com.softwaremagico.tm.random.selectors.PsiquePathLevelPreferences;
import com.softwaremagico.tm.random.selectors.SpecializationPreferences;
public class RandomPsiquePath extends RandomSelector {
private static final int TOTAL_PDF_PSI_ROWS = 7;
private int totalPowers;
public RandomPsiquePath(CharacterPlayer characterPlayer, Set preferences)
throws InvalidXmlElementException {
super(characterPlayer, preferences);
}
@Override
public void assign() throws InvalidRandomElementSelectedException, InvalidXmlElementException {
// Random number of paths.
final IGaussianDistribution pathNumber = PsiquePathLevelPreferences.getSelected(getPreferences());
final int totalPaths = pathNumber.randomGaussian();
totalPowers = getCharacterPlayer().getTotalSelectedPowers();
for (int i = totalPowers; i < totalPaths; i++) {
try {
final OccultismPath selectedOccultismPath = selectElementByWeight();
// Select a level of psique.
final int pathLevel = assignMaxLevelOfPath(selectedOccultismPath);
// Assign path to the character.
assignPowersOfPath(selectedOccultismPath, pathLevel);
removeElementWeight(selectedOccultismPath);
} catch (InvalidRandomElementSelectedException irese) {
// No elements to select, probably no power is available.
}
}
}
@Override
protected Collection getAllElements() throws InvalidXmlElementException {
return OccultismPathFactory.getInstance().getElements(getCharacterPlayer().getLanguage(), getCharacterPlayer().getModuleName());
}
@Override
protected int getWeight(OccultismPath element) throws InvalidRandomElementSelectedException {
// Other factions path are forbidden
if (!element.getFactionsAllowed().isEmpty()
&& !element.getFactionsAllowed().contains(getCharacterPlayer().getFaction())) {
throw new InvalidRandomElementSelectedException("Path '" + element + "' restricted to faction '"
+ element.getFactionsAllowed() + "'.");
}
// Only paths with psique level.
try {
for (final OccultismType occultismType : OccultismTypeFactory.getInstance().getElements(
getCharacterPlayer().getLanguage(), getCharacterPlayer().getModuleName())) {
if (getCharacterPlayer().getPsiqueLevel(occultismType) == 0) {
if (Objects.equals(element.getOccultismType(), occultismType)) {
throw new InvalidRandomElementSelectedException(
"Character must have a minimum psi level for path '" + element + "'.");
}
}
}
} catch (InvalidXmlElementException e) {
RandomGenerationLog.errorMessage(this.getClass().getName(), e);
}
// Combat psi characters prefer specific paths.
final CombatPreferences combatPreferences = CombatPreferences.getSelected(getPreferences());
if (combatPreferences == CombatPreferences.BELLIGERENT
&& (element.getId().equals("farHand") || element.getId().equals("soma"))) {
return FAIR_PROBABILITY;
}
return 1;
}
private int assignMaxLevelOfPath(OccultismPath path) throws InvalidXmlElementException {
// Use psique level preferences for the path level.
final IGaussianDistribution psiqueLevelSelector = PsiqueLevelPreferences.getSelected(getPreferences());
int maxLevelSelected = psiqueLevelSelector.randomGaussian();
if (maxLevelSelected > psiqueLevelSelector.maximum()) {
maxLevelSelected = psiqueLevelSelector.maximum();
}
if (maxLevelSelected > getCharacterPlayer().getPsiqueLevel(path.getOccultismType())) {
maxLevelSelected = getCharacterPlayer().getPsiqueLevel(path.getOccultismType());
}
return maxLevelSelected;
}
private void assignPowersOfPath(OccultismPath path, int maxLevelSelected) throws InvalidXmlElementException {
final DifficultLevelPreferences difficultyLevel = DifficultLevelPreferences.getSelected(getPreferences());
int remainingPoints = FreeStyleCharacterCreation
.getFreeAvailablePoints(getCharacterPlayer().getInfo().getAge())
- CostCalculator.getCost(getCharacterPlayer(), difficultyLevel.getSkillsBonus(),
difficultyLevel.getCharacteristicsBonus());
// Select powers to set.
final List powersToAdd = new ArrayList<>();
final SpecializationPreferences specializationPreferences = SpecializationPreferences
.getSelected(getPreferences());
// Psi must have at least one power by level.
if (Objects.equals(path.getOccultismType(),
OccultismTypeFactory.getPsi(getCharacterPlayer().getLanguage(), getCharacterPlayer().getModuleName()))) {
for (int i = 1; i <= maxLevelSelected; i++) {
final List powers = new ArrayList<>(path.getPowersOfLevel(i));
// If has more than one power at one level, choose one of them
// at least.
if (!powers.isEmpty()) {
Collections.shuffle(powers);
powersToAdd.add(powers.get(0));
}
}
}
// Theurgy does not need to have all levels.
if (Objects.equals(path.getOccultismType(), OccultismTypeFactory.getTheurgy(getCharacterPlayer().getLanguage(),
getCharacterPlayer().getModuleName()))) {
// Levels to add.
final int numberOfPowers = specializationPreferences.randomGaussian();
final List powers = new ArrayList<>(path.getOccultismPowers().values());
Collections.shuffle(powers);
while (numberOfPowers > 0 && !powers.isEmpty()) {
// It is possible to add this power.
if (powers.get(0).getLevel() <= maxLevelSelected) {
powersToAdd.add(powers.get(0));
}
powers.remove(0);
}
}
// Add selected powers if enough point
for (final OccultismPower power : powersToAdd) {
// Enough points
if (totalPowers >= TOTAL_PDF_PSI_ROWS) {
RandomGenerationLog.info(this.getClass().getName(), "No more psi power room is left.");
break;
}
if (remainingPoints - power.getLevel() * CostCalculator.PATH_LEVEL_COST >= 0) {
getCharacterPlayer().addOccultismPower(power);
RandomGenerationLog.info(this.getClass().getName(), "Assinged power '" + power + "' to path '" + path
+ "'.");
remainingPoints -= power.getLevel() * CostCalculator.PATH_LEVEL_COST;
totalPowers++;
}
}
}
@Override
protected void assignIfMandatory(OccultismPath path) throws InvalidXmlElementException,
ImpossibleToAssignMandatoryElementException {
// Own factions paths are a must.
if (path.getFactionsAllowed().contains(getCharacterPlayer().getFaction())) {
// Select a level of psique.
final int pathLevel = assignMaxLevelOfPath(path);
// Assign path to the character.
assignPowersOfPath(path, pathLevel);
removeElementWeight(path);
}
}
@Override
protected void assignMandatoryValues(Set mandatoryValues) throws InvalidXmlElementException {
return;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy