All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.softwaremagico.tm.character.occultism.RandomPsiquePath Maven / Gradle / Ivy

There is a newer version: 0.10.5
Show newest version
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