Added poo2.

This commit is contained in:
lucic71 2020-05-07 09:56:22 +03:00
parent 4fbe09e71f
commit e1a7391ecc
50 changed files with 3117 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,45 @@
package angel;
public abstract class AbstractAngel implements VisitorAngel{
private String name;
private int posX;
private int posY;
private String identifier;
public AbstractAngel(final String name, final int posX, final int posY,
String identifier) {
this.name = name;
this.posX = posX;
this.posY = posY;
this.identifier = identifier;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
public String getIdentifier() {
return identifier;
}
}

View File

@ -0,0 +1,73 @@
package angel;
public final class AngelConstants {
// --> DamageAngel constants
public static float DAMAGEANGEL_KNIGHT_MOD = 0.15F;
public static float DAMAGEANGEL_PYRO_MOD = 0.20F;
public static float DAMAGEANGEL_ROGUE_MOD = 0.30F;
public static float DAMAGEANGEL_WIZARD_MOD = 0.40F;
// --> DarkAngel constants
public static int DARKANGEL_KNIGHT_HP = 40;
public static int DARKANGEL_PYRO_HP = 30;
public static int DARKANGEL_ROGUE_HP = 10;
public static int DARKANGEL_WIZARD_HP = 20;
// --> Dracula constants
public static float DRACULA_KNIGHT_MOD = 0.20F;
public static float DRACULA_PYRO_MOD = 0.30F;
public static float DRACULA_ROGUE_MOD = 0.10F;
public static float DRACULA_WIZARD_MOD = 0.40F;
public static int DRACULA_KNIGHT_HP = 60;
public static int DRACULA_PYRO_HP = 40;
public static int DRACULA_ROGUE_HP = 35;
public static int DRACULA_WIZARD_HP = 20;
// --> GoodBoy constants
public static float GOODBOY_KNIGHT_MOD = 0.40F;
public static float GOODBOY_PYRO_MOD = 0.50F;
public static float GOODBOY_ROGUE_MOD = 0.40F;
public static float GOODBOY_WIZARD_MOD = 0.30F;
public static int GOODBOY_KNIGHT_HP = 20;
public static int GOODBOY_PYRO_HP = 30;
public static int GOODBOY_ROGUE_HP = 40;
public static int GOODBOY_WIZARD_HP = 50;
// --> LevelUpAngel constants
public static float LEVELUPANGEL_KNIGHT_MOD = 0.10F;
public static float LEVELUPANGEL_PYRO_MOD = 0.20F;
public static float LEVELUPANGEL_ROGUE_MOD = 0.15F;
public static float LEVELUPANGEL_WIZARD_MOD = 0.25F;
// --> LifeGiver constants
public static int LIFEGIVER_KNIGHT_HP = 100;
public static int LIFEGIVER_PYRO_HP = 80;
public static int LIFEGIVER_ROGUE_HP = 90;
public static int LIFEGIVER_WIZARD_HP = 120;
// --> SmallAngel constants
public static float SMALLANGEL_KNIGHT_MOD = 0.10F;
public static float SMALLANGEL_PYRO_MOD = 0.15F;
public static float SMALLANGEL_ROGUE_MOD = 0.05F;
public static float SMALLANGEL_WIZARD_MOD = 0.10F;
public static int SMALLANGEL_KNIGHT_HP = 10;
public static int SMALLANGEL_PYRO_HP = 15;
public static int SMALLANGEL_ROGUE_HP = 20;
public static int SMALLANGEL_WIZARD_HP = 25;
// --> Spawner constants
public static int SPAWNER_KNIGHT_HP = 200;
public static int SPAWNER_PYRO_HP = 150;
public static int SPAWNER_ROGUE_HP = 180;
public static int SPAWNER_WIZARD_HP = 120;
// --> XPAngel constants
public static int XPANGEL_KNIGHT_XP = 45;
public static int XPANGEL_PYRO_XP = 50;
public static int XPANGEL_ROGUE_XP = 40;
public static int XPANGEL_WIZARD_XP = 60;
}

View File

@ -0,0 +1,68 @@
package angel;
public final class AngelsFactory {
private static AngelsFactory instance = null;
private AngelsFactory() {}
public static AngelsFactory getInstance() {
if (instance == null) {
instance = new AngelsFactory();
}
return instance;
}
public AbstractAngel getAngel(final String angelName, final int posX, final int posY) {
AbstractAngel angel = null;
switch (angelName) {
case "DamageAngel" :
angel = new DamageAngel(angelName, posX, posY, "good");
break;
case "DarkAngel" :
angel = new DarkAngel(angelName, posX, posY, "bad");
break;
case "Dracula" :
angel = new Dracula(angelName, posX, posY, "bad");
break;
case "GoodBoy" :
angel = new GoodBoy(angelName, posX, posY, "good");
break;
case "LevelUpAngel" :
angel = new LevelUpAngel(angelName, posX, posY, "good");
break;
case "LifeGiver" :
angel = new LifeGiver(angelName, posX, posY, "good");
break;
case "SmallAngel" :
angel = new SmallAngel(angelName, posX, posY, "good");
break;
case "Spawner" :
angel = new Spawner(angelName, posX, posY, "good");
break;
case "TheDoomer" :
angel = new TheDoomer(angelName, posX, posY, "bad");
break;
case "XPAngel" :
angel = new XPAngel(angelName, posX, posY, "good");
break;
default:
System.err.println("Angel does not exist! Aborting..");
System.exit(-1);
break;
}
return angel;
}
}

View File

@ -0,0 +1,33 @@
package angel;
import hero.Knight;
import hero.Pyromancer;
import hero.Rogue;
import hero.Wizard;
public class DamageAngel extends AbstractAngel {
public DamageAngel(final String name, final int posX, final int posY,
String identifier) {
super(name, posX, posY, identifier);
}
@Override
public void applyAngelAbility(final Pyromancer pyromancer) {
pyromancer.setAngelMod(AngelConstants.DAMAGEANGEL_PYRO_MOD);
}
@Override
public void applyAngelAbility(final Knight knight) {
knight.setAngelMod(AngelConstants.DAMAGEANGEL_KNIGHT_MOD);
}
@Override
public void applyAngelAbility(final Rogue rogue) {
rogue.setAngelMod(AngelConstants.DAMAGEANGEL_ROGUE_MOD);
}
@Override
public void applyAngelAbility(final Wizard wizard) {
wizard.setAngelMod(AngelConstants.DAMAGEANGEL_WIZARD_MOD);
}
}

View File

@ -0,0 +1,33 @@
package angel;
import hero.Knight;
import hero.Pyromancer;
import hero.Rogue;
import hero.Wizard;
public class DarkAngel extends AbstractAngel{
public DarkAngel(final String name, final int posX, final int posY,
String identifier) {
super(name, posX, posY, identifier);
}
@Override
public void applyAngelAbility(final Pyromancer pyromancer) {
pyromancer.setHp(pyromancer.getHp() - AngelConstants.DARKANGEL_PYRO_HP);
}
@Override
public void applyAngelAbility(final Knight knight) {
knight.setHp(knight.getHp() - AngelConstants.DARKANGEL_KNIGHT_HP);
}
@Override
public void applyAngelAbility(final Rogue rogue) {
rogue.setHp(rogue.getHp() - AngelConstants.DARKANGEL_ROGUE_HP);
}
@Override
public void applyAngelAbility(final Wizard wizard) {
wizard.setHp(wizard.getHp() - AngelConstants.DARKANGEL_WIZARD_HP);
}
}

View File

@ -0,0 +1,38 @@
package angel;
import hero.Knight;
import hero.Pyromancer;
import hero.Rogue;
import hero.Wizard;
public class Dracula extends AbstractAngel{
public Dracula(final String name, final int posX, final int posY,
String identifier) {
super(name, posX, posY, identifier);
}
@Override
public void applyAngelAbility(final Pyromancer pyromancer) {
pyromancer.setAngelMod(-AngelConstants.DRACULA_PYRO_MOD);
pyromancer.setHp(pyromancer.getHp() - AngelConstants.DRACULA_PYRO_HP);
}
@Override
public void applyAngelAbility(final Knight knight) {
knight.setAngelMod(-AngelConstants.DRACULA_KNIGHT_MOD);
knight.setHp(knight.getHp() - AngelConstants.DRACULA_KNIGHT_HP);
}
@Override
public void applyAngelAbility(final Rogue rogue) {
rogue.setAngelMod(-AngelConstants.DRACULA_ROGUE_MOD);
rogue.setHp(rogue.getHp() - AngelConstants.DRACULA_ROGUE_HP);
}
@Override
public void applyAngelAbility(final Wizard wizard) {
wizard.setAngelMod(-AngelConstants.DRACULA_WIZARD_MOD);
wizard.setHp(wizard.getHp() - AngelConstants.DRACULA_WIZARD_HP);
}
}

View File

@ -0,0 +1,82 @@
package angel;
import hero.Knight;
import hero.Pyromancer;
import hero.Rogue;
import hero.Wizard;
public class GoodBoy extends AbstractAngel {
public GoodBoy(final String name, final int posX, final int posY,
String identifier) {
super(name, posX, posY, identifier);
}
@Override
public void applyAngelAbility(final Pyromancer pyromancer) {
pyromancer.setAngelMod(AngelConstants.GOODBOY_PYRO_MOD);
int levelMaxHp = pyromancer.getMaxHp() + pyromancer.getLevel() * pyromancer.getLevelBonusHp();
if (pyromancer.getHp() >= levelMaxHp) {
return;
}
int newHp = pyromancer.getHp() + AngelConstants.GOODBOY_PYRO_HP;
if (newHp >= levelMaxHp) {
newHp = levelMaxHp;
}
pyromancer.setHp(newHp);
}
@Override
public void applyAngelAbility(final Knight knight) {
knight.setAngelMod(AngelConstants.GOODBOY_KNIGHT_MOD);
int levelMaxHp = knight.getMaxHp() + knight.getLevel() * knight.getLevelBonusHp();
if (knight.getHp() >= levelMaxHp) {
return;
}
int newHp = knight.getHp() + AngelConstants.GOODBOY_KNIGHT_HP;
if (newHp >= levelMaxHp) {
newHp = levelMaxHp;
}
knight.setHp(newHp);
}
@Override
public void applyAngelAbility(final Rogue rogue) {
rogue.setAngelMod(AngelConstants.GOODBOY_ROGUE_MOD);
int levelMaxHp = rogue.getMaxHp() + rogue.getLevel() * rogue.getLevelBonusHp();
if (rogue.getHp() >= levelMaxHp) {
return;
}
int newHp = rogue.getHp() + AngelConstants.GOODBOY_ROGUE_HP;
if (newHp >= levelMaxHp) {
newHp = levelMaxHp;
}
rogue.setHp(newHp);
}
@Override
public void applyAngelAbility(final Wizard wizard) {
wizard.setAngelMod(AngelConstants.GOODBOY_WIZARD_MOD);
int levelMaxHp = wizard.getMaxHp() + wizard.getLevel() * wizard.getLevelBonusHp();
if (wizard.getHp() >= levelMaxHp) {
return;
}
int newHp = wizard.getHp() + AngelConstants.GOODBOY_WIZARD_HP;
if (newHp >= levelMaxHp) {
newHp = levelMaxHp;
}
wizard.setHp(newHp);
}
}

View File

@ -0,0 +1,59 @@
package angel;
import engine.FightingEngine;
import great_magician.GreatMagician;
import hero.*;
import main.Main;
public class LevelUpAngel extends AbstractAngel {
private FightingEngine fightingEngine = new FightingEngine();
private GreatMagician greatMagician = new GreatMagician(Main.gameOutput);
public LevelUpAngel(final String name, final int posX, final int posY,
String identifier) {
super(name, posX, posY, identifier);
greatMagician.addLevelUpSubject(fightingEngine);
}
@Override
public void applyAngelAbility(final Pyromancer pyromancer) {
levelUpHero(pyromancer);
pyromancer.setAngelMod(AngelConstants.LEVELUPANGEL_PYRO_MOD);
}
@Override
public void applyAngelAbility(final Knight knight) {
levelUpHero(knight);
knight.setAngelMod(AngelConstants.LEVELUPANGEL_KNIGHT_MOD);
}
@Override
public void applyAngelAbility(final Rogue rogue) {
levelUpHero(rogue);
rogue.setAngelMod(AngelConstants.LEVELUPANGEL_ROGUE_MOD);
}
@Override
public void applyAngelAbility(final Wizard wizard) {
levelUpHero(wizard);
wizard.setAngelMod(AngelConstants.LEVELUPANGEL_WIZARD_MOD);
}
private void levelUpHero(final AbstractHero hero) {
// if xp is lower than 250 then set xp to 250 and level up
if (hero.getXp() < HeroConstants.LEVEL_GROWTH_BASE) {
hero.setXp(HeroConstants.LEVEL_GROWTH_BASE);
fightingEngine.executeLevelGrowth(hero);
} else {
// find next multiple of 50 and level up
int neededXp = ((hero.getXp() + HeroConstants.LEVEL_GROWTH_EXPONENT - 1)
/ HeroConstants.LEVEL_GROWTH_EXPONENT) * HeroConstants.LEVEL_GROWTH_EXPONENT;
if (neededXp == hero.getXp()) {
neededXp += HeroConstants.LEVEL_GROWTH_EXPONENT;
}
hero.setXp(neededXp);
fightingEngine.executeLevelGrowth(hero);
}
}
}

View File

@ -0,0 +1,72 @@
package angel;
import hero.Knight;
import hero.Pyromancer;
import hero.Rogue;
import hero.Wizard;
public class LifeGiver extends AbstractAngel {
public LifeGiver(final String name, final int posX, final int posY,
String identifier) {
super(name, posX, posY, identifier);
}
@Override
public void applyAngelAbility(final Pyromancer pyromancer) {
int levelMaxHp = pyromancer.getMaxHp() + pyromancer.getLevel() * pyromancer.getLevelBonusHp();
if (pyromancer.getHp() >= levelMaxHp) {
return;
}
int newHp = pyromancer.getHp() + AngelConstants.LIFEGIVER_PYRO_HP;
if (newHp >= levelMaxHp) {
newHp = levelMaxHp;
}
pyromancer.setHp(newHp);
}
@Override
public void applyAngelAbility(final Knight knight) {
int levelMaxHp = knight.getMaxHp() + knight.getLevel() * knight.getLevelBonusHp();
if (knight.getHp() >= levelMaxHp) {
return;
}
int newHp = knight.getHp() + AngelConstants.LIFEGIVER_KNIGHT_HP;
if (newHp >= levelMaxHp) {
newHp = levelMaxHp;
}
knight.setHp(newHp);
}
@Override
public void applyAngelAbility(final Rogue rogue) {
int levelMaxHp = rogue.getMaxHp() + rogue.getLevel() * rogue.getLevelBonusHp();
if (rogue.getHp() >= levelMaxHp) {
return;
}
int newHp = rogue.getHp() + AngelConstants.LIFEGIVER_ROGUE_HP;
if (newHp >= levelMaxHp) {
newHp = levelMaxHp;
}
rogue.setHp(newHp);
}
@Override
public void applyAngelAbility(final Wizard wizard) {
int levelMaxHp = wizard.getMaxHp() + wizard.getLevel() * wizard.getLevelBonusHp();
if (wizard.getHp() >= levelMaxHp) {
return;
}
int newHp = wizard.getHp() + AngelConstants.LIFEGIVER_WIZARD_HP;
if (newHp >= levelMaxHp) {
newHp = levelMaxHp;
}
wizard.setHp(newHp);
}
}

View File

@ -0,0 +1,38 @@
package angel;
import hero.Knight;
import hero.Pyromancer;
import hero.Rogue;
import hero.Wizard;
public class SmallAngel extends AbstractAngel {
public SmallAngel(final String name, final int posX, final int posY,
String identifier) {
super(name, posX, posY, identifier);
}
@Override
public void applyAngelAbility(final Pyromancer pyromancer) {
pyromancer.setAngelMod(AngelConstants.SMALLANGEL_PYRO_MOD);
pyromancer.setHp(pyromancer.getHp() + AngelConstants.SMALLANGEL_PYRO_HP);
}
@Override
public void applyAngelAbility(final Knight knight) {
knight.setAngelMod(AngelConstants.SMALLANGEL_KNIGHT_MOD);
knight.setHp(knight.getHp() + AngelConstants.SMALLANGEL_KNIGHT_HP);
}
@Override
public void applyAngelAbility(final Rogue rogue) {
rogue.setAngelMod(AngelConstants.SMALLANGEL_ROGUE_MOD);
rogue.setHp(rogue.getHp() + AngelConstants.SMALLANGEL_ROGUE_HP);
}
@Override
public void applyAngelAbility(final Wizard wizard) {
wizard.setAngelMod(AngelConstants.SMALLANGEL_WIZARD_MOD);
wizard.setHp(wizard.getHp() + AngelConstants.SMALLANGEL_WIZARD_HP);
}
}

View File

@ -0,0 +1,36 @@
package angel;
import hero.Knight;
import hero.Pyromancer;
import hero.Rogue;
import hero.Wizard;
public class Spawner extends AbstractAngel {
public Spawner(final String name, final int posX, final int posY,
String identifier) {
super(name, posX, posY, identifier);
}
@Override
public void applyAngelAbility(final Pyromancer pyromancer) {
pyromancer.setAlive(true);
pyromancer.setHp(AngelConstants.SPAWNER_PYRO_HP);
}
@Override
public void applyAngelAbility(final Knight knight) {
knight.setAlive(true);
knight.setHp(AngelConstants.SPAWNER_KNIGHT_HP);
}
@Override
public void applyAngelAbility(final Rogue rogue) {
rogue.setAlive(true);
rogue.setHp(AngelConstants.SPAWNER_ROGUE_HP);
}
@Override
public void applyAngelAbility(final Wizard wizard) {
wizard.setAlive(true);
wizard.setHp(AngelConstants.SPAWNER_WIZARD_HP);
}
}

View File

@ -0,0 +1,36 @@
package angel;
import engine.FightingEngine;
import hero.Knight;
import hero.Pyromancer;
import hero.Rogue;
import hero.Wizard;
public class TheDoomer extends AbstractAngel {
private FightingEngine fightingEngine = new FightingEngine();
public TheDoomer(final String name, final int posX, final int posY,
String identifier) {
super(name, posX, posY, identifier);
}
@Override
public void applyAngelAbility(final Pyromancer pyromancer) {
fightingEngine.purgeHero(pyromancer);
}
@Override
public void applyAngelAbility(final Knight knight) {
fightingEngine.purgeHero(knight);
}
@Override
public void applyAngelAbility(final Rogue rogue) {
fightingEngine.purgeHero(rogue);
}
@Override
public void applyAngelAbility(final Wizard wizard) {
fightingEngine.purgeHero(wizard);
}
}

View File

@ -0,0 +1,13 @@
package angel;
import hero.Knight;
import hero.Pyromancer;
import hero.Rogue;
import hero.Wizard;
public interface VisitorAngel {
void applyAngelAbility(Pyromancer pyromancer);
void applyAngelAbility(Knight knight);
void applyAngelAbility(Rogue rogue);
void applyAngelAbility(Wizard wizard);
}

View File

@ -0,0 +1,43 @@
package angel;
import engine.FightingEngine;
import great_magician.GreatMagician;
import hero.Knight;
import hero.Pyromancer;
import hero.Rogue;
import hero.Wizard;
import main.Main;
public class XPAngel extends AbstractAngel {
private FightingEngine fightingEngine = new FightingEngine();
private GreatMagician greatMagician = new GreatMagician(Main.gameOutput);
public XPAngel(final String name, final int posX, final int posY,
String identifier) {
super(name, posX, posY, identifier);
greatMagician.addLevelUpSubject(fightingEngine);
}
@Override
public void applyAngelAbility(final Pyromancer pyromancer) {
pyromancer.setXp(pyromancer.getXp() + AngelConstants.XPANGEL_PYRO_XP);
fightingEngine.executeLevelGrowth(pyromancer);
}
@Override
public void applyAngelAbility(final Knight knight) {
knight.setXp(knight.getXp() + AngelConstants.XPANGEL_KNIGHT_XP);
fightingEngine.executeLevelGrowth(knight);
}
@Override
public void applyAngelAbility(final Rogue rogue) {
rogue.setXp(rogue.getXp() + AngelConstants.XPANGEL_ROGUE_XP);
fightingEngine.executeLevelGrowth(rogue);
}
@Override
public void applyAngelAbility(final Wizard wizard) {
wizard.setXp(wizard.getXp() + AngelConstants.XPANGEL_WIZARD_XP);
fightingEngine.executeLevelGrowth(wizard);
}
}

View File

@ -0,0 +1,25 @@
package engine;
import great_magician.Observer;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractSubject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer o) {
observers.add(o);
}
public List<Observer> getObservers() {
return observers;
}
public abstract void notifyObserversRoundNumber();
public abstract void notifyObserversDeadHero();
public abstract void notifyObserversSpawnedAngel();
public abstract void notifyObserversAngelAbility();
public abstract void notifyObserverLevelUp();
public abstract void notifyLifeState();
}

View File

@ -0,0 +1,130 @@
package engine;
import angel.AbstractAngel;
import angel.Spawner;
import angel.TheDoomer;
import great_magician.Observer;
import hero.AbstractHero;
import java.util.List;
public class AngelEngine extends AbstractSubject {
private AbstractAngel spawnedAngel;
private AbstractHero affectedHero;
private AbstractHero changedLifeStateHero;
public void visitHeroes(List<AbstractAngel> abstractAngels,
List<AbstractHero> abstractHeroes) {
for (AbstractAngel angel : abstractAngels) {
spawnedAngel = angel;
notifyObserversSpawnedAngel();
for (AbstractHero hero : abstractHeroes) {
affectedHero = hero;
/* special cases when either the hero may be dead and the angel is
a Spawner or the hero may be alive and the hero is a TheDoomer
*/
if (angel instanceof Spawner && !hero.isAlive()
&& angel.getPosX() == hero.getPosX() && angel.getPosY()
== hero.getPosY()) {
changedLifeStateHero = hero;
hero.acceptAngelAbility(angel);
notifyObserversAngelAbility();
notifyLifeState();
continue;
} else if (angel instanceof Spawner && hero.isAlive()
&& angel.getPosX() == hero.getPosX() && angel.getPosY()
== hero.getPosY()) {
continue;
}
if (angel instanceof TheDoomer && hero.isAlive()
&& angel.getPosX() == hero.getPosX() && angel.getPosY()
== hero.getPosY()) {
changedLifeStateHero = hero;
hero.acceptAngelAbility(angel);
notifyObserversAngelAbility();
notifyLifeState();
continue;
} else if (angel instanceof TheDoomer && !hero.isAlive()
&& angel.getPosX() == hero.getPosX() && angel.getPosY()
== hero.getPosY()) {
continue;
}
// flag that checks if the hero is still alive after a bad
// angel applied its ability
boolean heroStillAlive = true;
if (hero.isAlive() && angel.getPosX() == hero.getPosX()
&& angel.getPosY() == hero.getPosY()) {
notifyObserversAngelAbility();
hero.acceptAngelAbility(angel);
if (!hero.isAlive()) {
heroStillAlive = false;
}
}
// if the hero was killed by an angel
if (!heroStillAlive) {
changedLifeStateHero = hero;
notifyLifeState();
}
}
}
}
public AbstractAngel getSpawnedAngel() {
return spawnedAngel;
}
public AbstractHero getAffectedHero() {
return affectedHero;
}
public AbstractHero getChangedLifeStateHero() {
return changedLifeStateHero;
}
@Override
public void notifyObserversRoundNumber() {
}
@Override
public void notifyObserversDeadHero() {
}
@Override
public void notifyObserversSpawnedAngel() {
for (Observer o : getObservers()) {
o.updateSpawnedAngel();
}
}
@Override
public void notifyObserversAngelAbility() {
for (Observer o : getObservers()) {
o.updateAngelAbility();
}
}
@Override
public void notifyObserverLevelUp() {
}
@Override
public void notifyLifeState() {
for (Observer o : getObservers()) {
o.updateLifeState();
}
}
}

View File

@ -0,0 +1,227 @@
package engine;
import great_magician.Observer;
import hero.AbstractHero;
import hero.HeroConstants;
import java.util.List;
public class FightingEngine extends AbstractSubject {
private AbstractHero stateKillerHero;
private AbstractHero stateKilledHero;
private int oldLevel;
private int newLevel;
private AbstractHero levelUpHero;
final void fight(final List<List<Character>> map, final List<AbstractHero> heroList) {
for (int i = 0; i < map.size(); i++) {
for (int j = 0; j < map.get(i).size(); j++) {
fightAtPosition(heroList, i, j);
}
}
}
private void fightAtPosition(final List<AbstractHero> heroList, final int i,
final int j) {
// check if there are 2 players on a position
int numberOfPlayersAtPosition = 0;
AbstractHero hero1 = null;
AbstractHero hero2 = null;
for (AbstractHero hero : heroList) {
if (hero.getPosX() == i && hero.getPosY() == j && hero.isAlive()) {
numberOfPlayersAtPosition++;
if (numberOfPlayersAtPosition == 1) {
hero1 = hero;
}
if (numberOfPlayersAtPosition == 2) {
hero2 = hero;
}
}
}
if (numberOfPlayersAtPosition != 2) {
return;
}
// if hero2 is wizard swap the positions because the program
// needs to know the total damage without modifiers of the other
// hero
if (hero2.getCharIdentifier() == 'W') {
AbstractHero temp = hero2;
hero2 = hero1;
hero1 = temp;
}
executeAbilities(hero1, hero2);
}
final protected void executeDamageOverTime(List<AbstractHero> heroList) {
for (AbstractHero hero : heroList) {
this.executeOverTimeDamage(hero);
}
}
private void executeAbilities(final AbstractHero hero1, final AbstractHero hero2) {
if (hero1.getNumberIdentifier() == 7 || hero2.getNumberIdentifier() == 7) {
System.out.print("** ");
}
System.out.println(hero1.getCharIdentifier() + " " + hero1.getNumberIdentifier()
+ " fights " + hero2.getCharIdentifier() + " " + hero2.getNumberIdentifier());
int damageOfHero1 = hero1.acceptDamage(hero2);
int damageOfHero2 = hero2.acceptDamage(hero1);
int currentHpHero1 = hero1.getHp();
int currentHpHero2 = hero2.getHp();
hero1.setHp(currentHpHero1 - damageOfHero1);
hero2.setHp(currentHpHero2 - damageOfHero2);
// both die; first dies; second dies
if (hero1.getHp() <= 0 && hero2.getHp() <= 0) {
stateKillerHero = hero1;
stateKilledHero = hero2;
notifyObserversDeadHero();
stateKillerHero = hero2;
stateKilledHero = hero1;
notifyObserversDeadHero();
purgeHero(hero2);
purgeHero(hero1);
} else if (hero1.getHp() <= 0) {
stateKillerHero = hero2;
stateKilledHero = hero1;
notifyObserversDeadHero();
purgeHero(hero1);
executeXpGrowth(hero2, hero1);
executeLevelGrowth(hero2);
} else if (hero2.getHp() <= 0) {
stateKillerHero = hero1;
stateKilledHero = hero2;
notifyObserversDeadHero();
purgeHero(hero2);
executeXpGrowth(hero1, hero2);
executeLevelGrowth(hero1);
}
}
private void executeOverTimeDamage(final AbstractHero hero) {
if (hero.getOverTimeRounds() != 0) {
int currentHp = hero.getHp();
// if the new resulting hp is less than 0 the hero
// clearly died
if (currentHp - hero.getOverTimeDamage() <= 0) {
purgeHero(hero);
return;
} else {
hero.setHp(currentHp - hero.getOverTimeDamage());
}
int currentOverTimeRounds = hero.getOverTimeRounds();
hero.setOverTimeRounds(currentOverTimeRounds - 1);
if (hero.getOverTimeRounds() == 0) {
hero.setOverTimeDamage(0);
}
}
}
private void executeXpGrowth(final AbstractHero winner, final AbstractHero loser) {
int xpWinner = winner.getXp() + Math.max(0, HeroConstants.XP_GROWTH_BASE
- (winner.getLevel() - loser.getLevel()) * HeroConstants.XP_GROWTH_EXPONENT);
winner.setXp(xpWinner);
}
public void executeLevelGrowth(final AbstractHero hero) {
if (hero.getXp() < HeroConstants.LEVEL_GROWTH_BASE) {
hero.setLevel(0);
} else {
int level = (hero.getXp() - HeroConstants.LEVEL_GROWTH_BASE)
/ HeroConstants.LEVEL_GROWTH_EXPONENT;
level++;
newLevel = level;
oldLevel = hero.getLevel();
levelUpHero = hero;
hero.setLevel(level);
notifyObserverLevelUp();
// restore hp and add hp bonus
hero.setHp(hero.getMaxHp() + hero.getLevel() * hero.getLevelBonusHp());
}
}
public void purgeHero(final AbstractHero hero) {
hero.setAlive(false);
hero.setHp(0);
//hero.setFrozenTime(0);
//hero.setOverTimeRounds(0);
//hero.setFrozen(false);
//hero.setOverTimeDamage(0);
//hero.setXp(0);
}
@Override
public void notifyObserversRoundNumber() {}
@Override
public void notifyObserversDeadHero() {
for (Observer o : getObservers()) {
o.updateDeadPlayer();
}
}
@Override
public void notifyObserversSpawnedAngel() {}
@Override
public void notifyObserversAngelAbility() {}
@Override
public void notifyObserverLevelUp() {
for (Observer o : getObservers()) {
o.updateLevelUp();
}
}
@Override
public void notifyLifeState() {
}
public AbstractHero getStateKillerHero() {
return stateKillerHero;
}
public AbstractHero getStateKilledHero() {
return stateKilledHero;
}
public int getOldLevel() {
return oldLevel;
}
public int getNewLevel() {
return newLevel;
}
public AbstractHero getLevelUpHero() {
return levelUpHero;
}
}

View File

@ -0,0 +1,170 @@
package engine;
import angel.AbstractAngel;
import great_magician.GreatMagician;
import great_magician.Observer;
import hero.AbstractHero;
import hero.HeroesFactory;
import main.GameInput;
import main.Main;
import utils.Utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GameEngine extends AbstractSubject {
private List<AbstractHero> heroList;
private List<String> angelString;
private List<List<Character>> map;
private List<String> rounds;
private int currentRound;
private final GreatMagician greatMagician = new GreatMagician(Main.gameOutput);
/**
GameEngine constructor stores a list of heroes that will
be later used in @play method. Also it saves the map and
the number of rounds. This info is parsed from a GameInput
object declared in #main.GameInput.
*/
public GameEngine(final GameInput input) {
heroList = new ArrayList<>();
HeroesFactory factory = HeroesFactory.getInstance();
// set heroes for the game
for (String hero : input.getHeroes()) {
List<String> heroAsStrList = Arrays.asList(hero.split(" "));
assert heroAsStrList.size() == 3 : "Not enough info to create a hero!";
String name = heroAsStrList.get(0);
int posX = Integer.parseInt(heroAsStrList.get(1));
int posY = Integer.parseInt(heroAsStrList.get(2));
heroList.add(factory.getHero(name, posX, posY));
}
// receive the angels as strings
this.angelString = input.getAngels();
// set the map for the game
map = input.getMap();
// set rounds for the game
rounds = input.getRounds();
}
/**
* The #GameEngine.play method simulates each round of the game,
* moving the players to their desired position and then calling
* the fight method from Fighting class. This class mainly focuses
* on handling the battles on each position in the map.
*
* @return: a list of type AbstractHero that contains all info
* needed at the end of the game.
*/
public List<AbstractHero> play() {
MovementEngine movementEngine = new MovementEngine();
FightingEngine fightingEngine = new FightingEngine();
AngelEngine angelEngine = new AngelEngine();
greatMagician.addDeadPlayerSubject(fightingEngine);
greatMagician.addRoundNumberSubject(this);
greatMagician.addSpawnedAngelSubject(angelEngine);
greatMagician.addAngelAbilitySubject(angelEngine);
greatMagician.addLevelUpSubject(fightingEngine);
greatMagician.addLifeStateSubject(angelEngine);
// move the players
for (int roundIt = 0; roundIt < rounds.size(); roundIt++) {
currentRound = roundIt + 1;
notifyObserversRoundNumber();
// dot
fightingEngine.executeDamageOverTime(heroList);
// movement
for (int i = 0; i < rounds.get(roundIt).length(); i++) {
char direction = rounds.get(roundIt).charAt(i);
AbstractHero hero = heroList.get(i);
// skip if the hero is dead
if (!hero.isAlive()) {
continue;
}
// if the hero is frozen do not move
if (!hero.isFrozen()) {
movementEngine.move(hero, direction);
int newPosX = hero.getPosX();
int newPosY = hero.getPosY();
hero.setCurrentTerrain(map.get(newPosX).get(newPosY));
// apply strategy
hero.applyStrategy();
} else {
int currentFrozenTime = hero.getFrozenTime();
hero.setFrozenTime(currentFrozenTime - 1);
if (hero.getFrozenTime() == 0) {
hero.setFrozen(false);
}
}
}
// fight
fightingEngine.fight(map, heroList);
// set angels for this round
List<AbstractAngel> angelList =
Utils.strListToAbstrAngelList(angelString.get(roundIt));
// angels visit heroes
angelEngine.visitHeroes(angelList, heroList);
}
return this.heroList;
}
public int getCurrentRound() {
return currentRound;
}
@Override
public void notifyObserversRoundNumber() {
for (Observer o : getObservers()) {
o.updateRoundNumber();
}
}
@Override
public void notifyObserversDeadHero() {
}
@Override
public void notifyObserversSpawnedAngel() {
}
@Override
public void notifyObserversAngelAbility() {
}
@Override
public void notifyObserverLevelUp() {
}
@Override
public void notifyLifeState() {
}
}

View File

@ -0,0 +1,28 @@
package engine;
import hero.AbstractHero;
class MovementEngine {
final void move(final AbstractHero hero, final char direction) {
switch (direction) {
case 'L' :
hero.setPosY(hero.getPosY() - 1);
break;
case 'R' :
hero.setPosY(hero.getPosY() + 1);
break;
case 'D' :
hero.setPosX(hero.getPosX() + 1);
break;
case 'U' :
hero.setPosX(hero.getPosX() - 1);
break;
default:
break;
}
}
}

View File

@ -0,0 +1,143 @@
package great_magician;
import angel.AbstractAngel;
import engine.AngelEngine;
import engine.FightingEngine;
import engine.GameEngine;
import hero.AbstractHero;
import main.GameOutput;
public class GreatMagician extends Observer {
private AbstractHero killedHero;
private AbstractHero killerHero;
private FightingEngine deadPlayerSubject;
private GameEngine roundNumberSubject;
private AngelEngine spawnedAngelSubject;
private AngelEngine angelAbilitySubject;
private FightingEngine levelUpSubject;
private AngelEngine lifeStateSubject;
private GameOutput gameOutput;
public GreatMagician(GameOutput gameOutput) {
this.gameOutput = gameOutput;
}
public void addDeadPlayerSubject(FightingEngine subject) {
this.deadPlayerSubject = subject;
if (!subject.getObservers().contains(this)) {
subject.attach(this);
}
}
public void addRoundNumberSubject(GameEngine subject) {
this.roundNumberSubject = subject;
if (!subject.getObservers().contains(this)) {
subject.attach(this);
}
}
public void addSpawnedAngelSubject(AngelEngine subject) {
this.spawnedAngelSubject = subject;
if (!subject.getObservers().contains(this)) {
subject.attach(this);
}
}
public void addAngelAbilitySubject(AngelEngine subject) {
this.angelAbilitySubject = subject;
if (!subject.getObservers().contains(this)) {
subject.attach(this);
}
}
public void addLevelUpSubject(FightingEngine subject) {
this.levelUpSubject = subject;
if (!subject.getObservers().contains(this)) {
subject.attach(this);
}
}
public void addLifeStateSubject(AngelEngine subject) {
this.lifeStateSubject = subject;
if (!subject.getObservers().contains(this)) {
subject.attach(this);
}
}
@Override
public void updateRoundNumber() {
gameOutput.writeRoundNumber(roundNumberSubject.getCurrentRound());
}
@Override
public void updateDeadPlayer() {
killedHero = deadPlayerSubject.getStateKilledHero();
killerHero = deadPlayerSubject.getStateKillerHero();
String killedHeroName = getHeroName(killedHero.getCharIdentifier());
String killerHeroName = getHeroName(killerHero.getCharIdentifier());
gameOutput.writeDeadPlayer(killedHero, killerHero, killedHeroName, killerHeroName);
}
@Override
public void updateSpawnedAngel() {
AbstractAngel angel = spawnedAngelSubject.getSpawnedAngel();
gameOutput.writeSpawnedAngel(angel.getName(), angel.getPosX(), angel.getPosY());
}
@Override
public void updateAngelAbility() {
AbstractHero hero = angelAbilitySubject.getAffectedHero();
AbstractAngel angel = angelAbilitySubject.getSpawnedAngel();
String action = null;
if (angel.getIdentifier().compareTo("good") == 0) {
action = "helped";
} else if (angel.getIdentifier().compareTo("bad") == 0) {
action = "hit";
}
gameOutput.writeAngelAbility(angel.getName(), action,
getHeroName(hero.getCharIdentifier()), hero.getNumberIdentifier());
}
@Override
public void updateLevelUp() {
int newLevel = levelUpSubject.getNewLevel();
int oldLevel = levelUpSubject.getOldLevel();
AbstractHero hero = levelUpSubject.getLevelUpHero();
for (int i = oldLevel + 1; i <= newLevel; i++) {
gameOutput.writeLevelUp(getHeroName(hero.getCharIdentifier()), hero.getNumberIdentifier(), i);
}
}
@Override
public void updateLifeState() {
AbstractHero hero = lifeStateSubject.getChangedLifeStateHero();
gameOutput.writeLifeStateHero(hero, getHeroName(hero.getCharIdentifier()));
}
private String getHeroName(Character identifier) {
String name = null;
switch (identifier) {
case 'W' :
name = "Wizard";
break;
case 'R' :
name = "Rogue";
break;
case 'K' :
name = "Knight";
break;
case 'P' :
name = "Pyromancer";
break;
}
return name;
}
}

View File

@ -0,0 +1,10 @@
package great_magician;
public abstract class Observer {
public abstract void updateRoundNumber();
public abstract void updateDeadPlayer();
public abstract void updateSpawnedAngel();
public abstract void updateAngelAbility();
public abstract void updateLevelUp();
public abstract void updateLifeState();
}

View File

@ -0,0 +1,275 @@
package hero;
import strategies.AbstractStrategy;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractHero implements
VisitableHero, VisitorHero, AngelVisitableHero{
// player stats
private int maxHp;
private boolean alive;
private int hp;
private int xp;
private int posX;
private int posY;
private int level;
private int levelBonusHp;
private Character specialTerrain;
private float terrainBonus;
private Character currentTerrain;
private Character charIdentifier;
private Integer numberIdentifier;
private int overTimeRounds;
private int overTimeDamage;
private boolean frozen;
private int frozenTime;
private int totalDamageWithoutRaceMod;
private float angelMod;
// player abilities
public abstract int firstAbility(AbstractHero victim);
public abstract int secondAbility(AbstractHero victim);
// player strategies
private List<AbstractStrategy> strategies;
private AbstractStrategy appliedStrategy;
public abstract void applyStrategy();
private float strategyMod;
// constructor
public AbstractHero(final int hp, final int xp, final int posX, final int posY, final int level,
final int levelBonusHp, final Character terrain, final float terrainBonus,
final Character charIdentifier, final int numberIdentifier) {
this.maxHp = hp;
this.alive = true;
this.hp = hp;
this.xp = xp;
this.posX = posX;
this.posY = posY;
this.level = level;
this.levelBonusHp = levelBonusHp;
this.specialTerrain = terrain;
this.terrainBonus = terrainBonus;
this.charIdentifier = charIdentifier;
this.numberIdentifier = numberIdentifier;
this.overTimeDamage = 0;
this.overTimeRounds = 0;
this.frozen = false;
this.frozenTime = 0;
this.angelMod = 0;
this.totalDamageWithoutRaceMod = 0;
this.strategies = new ArrayList<>();
}
// getters and setters
public final int getHp() {
return hp;
}
public final void setHp(final int hp) {
// guard for killing a hero
if (hp < 0) {
this.hp = 0;
this.setAlive(false);
return;
}
this.hp = hp;
}
public final int getXp() {
return xp;
}
public final void setXp(final int xp) {
this.xp = xp;
}
public final int getPosX() {
return posX;
}
public final void setPosX(final int posX) {
this.posX = posX;
}
public final int getPosY() {
return posY;
}
public final void setPosY(final int posY) {
this.posY = posY;
}
public final int getLevel() {
return level;
}
public final void setLevel(final int level) {
this.level = level;
}
public final int getLevelBonusHp() {
return levelBonusHp;
}
public final void setLevelBonusHp(final int levelBonusHp) {
this.levelBonusHp = levelBonusHp;
}
final Character getSpecialTerrain() {
return specialTerrain;
}
public final void setSpecialTerrain(final char specialTerrain) {
this.specialTerrain = specialTerrain;
}
final float getTerrainBonus() {
return terrainBonus;
}
public final void setTerrainBonus(final int terrainBonus) {
this.terrainBonus = terrainBonus;
}
public final Character getCharIdentifier() {
return charIdentifier;
}
final Character getCurrentTerrain() {
return currentTerrain;
}
public final void setCurrentTerrain(final Character currentTerrain) {
this.currentTerrain = currentTerrain;
}
public final int getOverTimeRounds() {
return overTimeRounds;
}
public final void setOverTimeRounds(final int overTimeRounds) {
this.overTimeRounds = overTimeRounds;
}
public final int getOverTimeDamage() {
return overTimeDamage;
}
public final void setOverTimeDamage(final int overTimeDamage) {
this.overTimeDamage = overTimeDamage;
}
public final boolean isFrozen() {
return frozen;
}
public final void setFrozen(final boolean frozen) {
this.frozen = frozen;
}
public final int getFrozenTime() {
return frozenTime;
}
public final void setFrozenTime(final int frozenTime) {
this.frozenTime = frozenTime;
}
public final int getMaxHp() {
return maxHp;
}
public final void setMaxHp(final int maxHp) {
this.maxHp = maxHp;
}
final int getTotalDamageWithoutRaceMod() {
return totalDamageWithoutRaceMod;
}
final void setTotalDamageWithoutRaceMod(final int totalDamageWithoutRaceMod) {
this.totalDamageWithoutRaceMod = totalDamageWithoutRaceMod;
}
public final boolean isAlive() {
return alive;
}
public final void setAlive(final boolean alive) {
this.alive = alive;
}
public float getAngelMod() {
return angelMod;
}
public void setAngelMod(float angelMod) {
this.angelMod += angelMod;
}
public void addStrategy(AbstractStrategy strategy) {
strategies.add(strategy);
}
public List<AbstractStrategy> getStrategies() {
return strategies;
}
public AbstractStrategy getAppliedStrategy() {
return appliedStrategy;
}
public void setAppliedStrategy(AbstractStrategy appliedStrategy) {
this.appliedStrategy = appliedStrategy;
}
public float getStrategyMod() {
return strategyMod;
}
public void setStrategyMod(float strategyMod) {
this.strategyMod = strategyMod;
}
public Integer getNumberIdentifier() {
return numberIdentifier;
}
@Override
public String toString() {
return "AbstractHero{" +
"maxHp=" + maxHp +
", hp=" + hp +
", posX=" + posX +
", posY=" + posY +
", level=" + level +
", numberIndentifier=" + numberIdentifier +
", overTimeRounds=" + overTimeRounds +
", overTimeDamage=" + overTimeDamage +
", frozen=" + frozen +
", frozenTime=" + frozenTime +
", appliedStrategy=" + appliedStrategy +
", strategyMod=" + strategyMod +
'}';
}
}

View File

@ -0,0 +1,7 @@
package hero;
import angel.AbstractAngel;
public interface AngelVisitableHero {
void acceptAngelAbility(AbstractAngel angel);
}

View File

@ -0,0 +1,129 @@
package hero;
public final class HeroConstants {
// pyromancer constants
static final int PYROINITHP = 500;
static final int PYROHPBONUS = 50;
static final Character PYROTERRAIN = 'V';
static final float PYROTERRAINBONUS = 1.25F;
// --> fireblast constants
static final int FIREBLAST_BASE_DAMAGE = 350;
static final int FIREBLAST_LVLBONUS_DAMAGE = 50;
static final float FIREBLAST_ROGUE_MOD = 0.8F;
static final float FIREBLAST_KNIGHT_MOD = 1.2F;
static final float FIREBLAST_PYROMANCER_MOD = 0.9F;
static final float FIREBLAST_WIZARD_MOD = 1.05F;
// --> ignite constants
static final int IGNITE_BASE_DAMAGE = 150;
static final int IGNITE_LVLBONUS_DAMAGE = 30;
static final float IGNITE_ROGUE_MOD = 0.8F;
static final float IGNITE_KNIGHT_MOD = 1.2F;
static final float IGNITE_PYROMANCER_MOD = 0.9F;
static final float IGNITE_WIZARD_MOD = 1.05F;
static final int IGNITE_OVERTIME_DAMAGE = 50;
static final int IGNITE_OVERTIME_DAMAGE_LVLBONUS = 30;
static final int IGNITE_OVERTIME_ROUNDS = 2;
// knight constants
static final int KNIGHTINITHP = 900;
static final int KNIGHTHPBONUS = 80;
static final Character KNIGHTTERRAIN = 'L';
static final float KNIGHTTERRAINBONUS = 1.15F;
// --> execute constants
static final int EXECUTE_BASE_DAMAGE = 200;
static final int EXECUTE_LVLBONUS_DAMAGE = 30;
static final float EXECUTE_ROGUE_MOD = 1.15F;
static final float EXECUTE_KNIGHT_MOD = 1.0F;
static final float EXECUTE_PYROMANCER_MOD = 1.10F;
static final float EXECUTE_WIZARD_MOD = 0.8F;
static final float EXECUTE_INITIAL_HP_LIMIT = 0.2F;
static final float EXECUTE_BONUS_HP_LIMIT = 0.01F;
static final float EXECUTE_UPPER_LIMIT = 0.4F;
// --> slam constants
static final int SLAM_BASE_DAMAGE = 100;
static final int SLAM_LVLBONUS_DAMAGE = 40;
static final float SLAM_ROGUE_MOD = 0.8F;
static final float SLAM_KNIGHT_MOD = 1.2F;
static final float SLAM_PYROMANCER_MOD = 0.90F;
static final float SLAM_WIZARD_MOD = 1.05F;
// wizard constants
static final int WIZARDINITHP = 400;
static final int WIZARDHPBONUS = 30;
static final Character WIZARDTERRAIN = 'D';
static final float WIZARDTERRAINBONUS = 1.10F;
// --> drain constants
static final float DRAIN_BASE_DAMAGE = 0.20F;
static final float DRAIN_LVLBONUS_DAMAGE = 0.05F;
static final float DRAIN_ROGUE_MOD = 0.8F;
static final float DRAIN_KNIGHT_MOD = 1.2F;
static final float DRAIN_PYROMANCER_MOD = 0.9F;
static final float DRAIN_WIZARD_MOD = 1.05F;
static final float DRAIN_MAX_HP_PERCENT = 0.3F;
// --> deflect constants
static final float DEFLECT_BASE_DAMAGE = 0.35F;
static final float DEFLECT_LVLBONUS_DAMAGE = 0.02F;
static final float DEFLECT_ROGUE_MOD = 1.2F;
static final float DEFLECT_KNIGHT_MOD = 1.4F;
static final float DEFLECT_PYROMANCER_MOD = 1.3F;
static final float DEFLECT_WIZARD_MOD = 0F;
static final float DEFLECT_MAX_BONUS_PERCENT = 0.70F;
// rogue constants
static final int ROGUEINITHP = 600;
static final int ROGUEHPBONUS = 40;
static final Character ROGUETERRAIN = 'W';
static final float ROGUETERRAINBONUS = 1.15F;
static final int CRITICAL_HIT_CYCLE = 3;
static final float CRITICAL_HIT_BONUS = 1.5F;
// --> backstab constants
static final int BACKSTAB_BASE_DAMAGE = 200;
static final int BACKSTAB_LVLBONUS_DAMAGE = 20;
static final float BACKSTAB_ROGUE_MOD = 1.2F;
static final float BACKSTAB_KNIGHT_MOD = 0.9F;
static final float BACKSTAB_PYROMANCER_MOD = 1.25F;
static final float BACKSTAB_WIZARD_MOD = 1.25F;
// --> paralysis constants
static final int PARALYSIS_BASE_DAMAGE = 40;
static final int PARALYSIS_LVLBONUS_DAMAGE = 10;
static final float PARALYSIS_ROGUE_MOD = 0.9F;
static final float PARALYSIS_KNIGHT_MOD = 0.8F;
static final float PARALYSIS_PYROMANCER_MOD = 1.2F;
static final float PARALYSIS_WIZARD_MOD = 1.25F;
static final int PARALYSIS_NORMAL_OVERTIME_ROUNDS = 3;
static final int PARALYSIS_EXTENDED_OVERTIME_ROUNDS = 6;
// --> level growth constants
public static final int LEVEL_GROWTH_BASE = 250;
public static final int LEVEL_GROWTH_EXPONENT = 50;
// --> xp growth constants
public static final int XP_GROWTH_BASE = 200;
public static final int XP_GROWTH_EXPONENT = 40;
}

View File

@ -0,0 +1,53 @@
package hero;
public final class HeroesFactory {
private static HeroesFactory instance = null;
private static int heroCounter = 0;
private HeroesFactory() {}
public static HeroesFactory getInstance() {
if (instance == null) {
instance = new HeroesFactory();
}
return instance;
}
public AbstractHero getHero(final String heroName, final int posX, final int posY) {
AbstractHero hero = null;
switch (heroName) {
case "W" :
hero = new Wizard(HeroConstants.WIZARDINITHP, 0, posX, posY,
0, HeroConstants.WIZARDHPBONUS, HeroConstants.WIZARDTERRAIN,
HeroConstants.WIZARDTERRAINBONUS, heroName.charAt(0), heroCounter++);
break;
case "R" :
hero = new Rogue(HeroConstants.ROGUEINITHP, 0, posX, posY,
0, HeroConstants.ROGUEHPBONUS, HeroConstants.ROGUETERRAIN,
HeroConstants.ROGUETERRAINBONUS, heroName.charAt(0), heroCounter++);
break;
case "K" :
hero = new Knight(HeroConstants.KNIGHTINITHP, 0, posX, posY,
0, HeroConstants.KNIGHTHPBONUS, HeroConstants.KNIGHTTERRAIN,
HeroConstants.KNIGHTTERRAINBONUS, heroName.charAt(0), heroCounter++);
break;
case "P" :
hero = new Pyromancer(HeroConstants.PYROINITHP, 0, posX, posY,
0, HeroConstants.PYROHPBONUS, HeroConstants.PYROTERRAIN,
HeroConstants.PYROTERRAINBONUS, heroName.charAt(0), heroCounter++);
break;
default :
System.err.println("Hero does not exist! Aborting..");
System.exit(-1);
break;
}
return hero;
}
}

View File

@ -0,0 +1,167 @@
package hero;
import angel.AbstractAngel;
import strategies.KnightDecreaseHpIncreaseMod;
import strategies.KnightIncreaseHpDecreaseMod;
import strategies.StrategySelector;
import java.util.Map;
public final class Knight extends AbstractHero{
public Knight(final int hp, final int xp, final int posX, final int posY, final int level,
final int levelBonusHp, final Character terrain, final float terrainBonus,
final Character identifier, final int numberIdentifier) {
super(hp, xp, posX, posY, level, levelBonusHp, terrain, terrainBonus,
identifier, numberIdentifier);
addStrategy(new KnightDecreaseHpIncreaseMod());
addStrategy(new KnightIncreaseHpDecreaseMod());
}
// execute
@Override
public int firstAbility(final AbstractHero victim) {
int baseDamage = HeroConstants.EXECUTE_BASE_DAMAGE;
int levelBonusDamage = HeroConstants.EXECUTE_LVLBONUS_DAMAGE * this.getLevel();
// base damage
float totalDamageFloat = baseDamage + levelBonusDamage;
// compute hp limit for critical damage
int theoreticalMaxHp = victim.getMaxHp() + victim.getLevel()
* victim.getLevelBonusHp();
// 1% per level
float hpLimitLevelBonusPercent = HeroConstants.EXECUTE_BONUS_HP_LIMIT
* this.getLevel();
float totalPercent = HeroConstants.EXECUTE_INITIAL_HP_LIMIT
+ hpLimitLevelBonusPercent;
// if the percent is greater than 40%
if (totalPercent > HeroConstants.EXECUTE_UPPER_LIMIT) {
totalPercent = HeroConstants.EXECUTE_UPPER_LIMIT;
}
// (20% + 1% * level) * theoretical max hp
float hpLimit = totalPercent * theoreticalMaxHp;
if (victim.getHp() < Math.round(hpLimit)) {
// land bonus
if (this.getCurrentTerrain() == this.getSpecialTerrain()) {
totalDamageFloat = totalDamageFloat * this.getTerrainBonus();
}
// damage without race mod
this.setTotalDamageWithoutRaceMod(Math.round(totalDamageFloat));
return victim.getHp();
}
// compute normal damage
// land bonus
if (this.getCurrentTerrain() == this.getSpecialTerrain()) {
totalDamageFloat = totalDamageFloat * this.getTerrainBonus();
}
// rounded after land bonus was applied
int totalDamage = Math.round(totalDamageFloat);
// damage without race mod
this.setTotalDamageWithoutRaceMod(totalDamage);
// race mod
Map<Character, Float> modTable = RaceModifierTable.getTable(
HeroConstants.EXECUTE_ROGUE_MOD,
HeroConstants.EXECUTE_KNIGHT_MOD,
HeroConstants.EXECUTE_PYROMANCER_MOD,
HeroConstants.EXECUTE_WIZARD_MOD, this);
totalDamage = Math.round(totalDamage * modTable.get(victim.getCharIdentifier()));
return totalDamage;
}
// slam
@Override
public int secondAbility(final AbstractHero victim) {
int baseDamage = HeroConstants.SLAM_BASE_DAMAGE;
int levelBonusDamage = this.getLevel() * HeroConstants.SLAM_LVLBONUS_DAMAGE;
// base damage
float totalDamageFloat = baseDamage + levelBonusDamage;
// land bonus
if (this.getCurrentTerrain() == this.getSpecialTerrain()) {
totalDamageFloat = totalDamageFloat * this.getTerrainBonus();
}
// rounded after land bonus was applied
int totalDamage = Math.round(totalDamageFloat);
// damage without race mod
this.setTotalDamageWithoutRaceMod(totalDamage
+ this.getTotalDamageWithoutRaceMod());
// race mod
Map<Character, Float> modTable = RaceModifierTable.getTable(
HeroConstants.SLAM_ROGUE_MOD,
HeroConstants.SLAM_KNIGHT_MOD,
HeroConstants.SLAM_PYROMANCER_MOD,
HeroConstants.SLAM_WIZARD_MOD, this);
totalDamage = Math.round(totalDamageFloat * modTable.get(victim.getCharIdentifier()));
// frozen
victim.setFrozen(true);
victim.setFrozenTime(1);
return totalDamage;
}
@Override
public void applyStrategy() {
StrategySelector.selectStrategy(this);
if (getAppliedStrategy() != null) {
getAppliedStrategy().algorithm(this);
}
}
@Override
public int acceptDamage(final VisitorHero v) {
return v.giveDamage(this);
}
@Override
public int giveDamage(final Pyromancer pyromancer) {
return this.firstAbility(pyromancer)
+ this.secondAbility(pyromancer);
}
@Override
public int giveDamage(final Knight knight) {
return this.firstAbility(knight)
+ this.secondAbility(knight);
}
@Override
public int giveDamage(final Rogue rogue) {
return this.firstAbility(rogue)
+ this.secondAbility(rogue);
}
@Override
public int giveDamage(final Wizard wizard) {
return this.firstAbility(wizard)
+ this.secondAbility(wizard);
}
@Override
public void acceptAngelAbility(final AbstractAngel angel) {
angel.applyAngelAbility(this);
}
}

View File

@ -0,0 +1,141 @@
package hero;
import angel.AbstractAngel;
import strategies.PyroDecreaseHpIncreaseMod;
import strategies.PyroIncreaseHpDecreaseMod;
import strategies.StrategySelector;
import java.util.Map;
public final class Pyromancer extends AbstractHero {
public Pyromancer(final int hp, final int xp, final int posX, final int posY, final int level,
final int levelBonusHp, final Character terrain, final float terrainBonus,
final Character identifier, final int numberIdentifier) {
super(hp, xp, posX, posY, level, levelBonusHp, terrain, terrainBonus,
identifier, numberIdentifier);
addStrategy(new PyroDecreaseHpIncreaseMod());
addStrategy(new PyroIncreaseHpDecreaseMod());
}
// fireblast
@Override
public int firstAbility(final AbstractHero victim) {
int baseDamage = HeroConstants.FIREBLAST_BASE_DAMAGE;
int levelBonusDamage = this.getLevel() * HeroConstants.FIREBLAST_LVLBONUS_DAMAGE;
// base damage
float totalDamageFloat = baseDamage + levelBonusDamage;
// land bonus
if (this.getCurrentTerrain() == this.getSpecialTerrain()) {
totalDamageFloat = totalDamageFloat * this.getTerrainBonus();
}
// rounded after land bonus was applied
int totalDamage = Math.round(totalDamageFloat);
// damage without race mod
this.setTotalDamageWithoutRaceMod(totalDamage);
// race mod
Map<Character, Float> modTable = RaceModifierTable.getTable(
HeroConstants.FIREBLAST_ROGUE_MOD,
HeroConstants.FIREBLAST_KNIGHT_MOD,
HeroConstants.FIREBLAST_PYROMANCER_MOD,
HeroConstants.FIREBLAST_WIZARD_MOD, this);
totalDamage = Math.round(totalDamage * modTable.get(victim.getCharIdentifier()));
return totalDamage;
}
// ignite
@Override
public int secondAbility(final AbstractHero victim) {
int baseDamage = HeroConstants.IGNITE_BASE_DAMAGE;
int levelBonusDamage = this.getLevel() * HeroConstants.IGNITE_LVLBONUS_DAMAGE;
// base damage
float totalDamageFloat = baseDamage + levelBonusDamage;
// overtime damage
float periodicDamageFloat = HeroConstants.IGNITE_OVERTIME_DAMAGE
+ HeroConstants.IGNITE_OVERTIME_DAMAGE_LVLBONUS * this.getLevel();
// land bonus
if (this.getCurrentTerrain() == this.getSpecialTerrain()) {
totalDamageFloat = totalDamageFloat * this.getTerrainBonus();
periodicDamageFloat = periodicDamageFloat * this.getTerrainBonus();
}
// rounded after land bonus was applied
int totalDamage = Math.round(totalDamageFloat);
int periodicDamage = Math.round(periodicDamageFloat);
// damage without race mod
this.setTotalDamageWithoutRaceMod(totalDamage
+ this.getTotalDamageWithoutRaceMod());
// race mod
Map<Character, Float> modTable = RaceModifierTable.getTable(HeroConstants.IGNITE_ROGUE_MOD,
HeroConstants.IGNITE_KNIGHT_MOD,
HeroConstants.IGNITE_PYROMANCER_MOD,
HeroConstants.IGNITE_WIZARD_MOD, this);
totalDamage = Math.round(totalDamage * modTable.get(victim.getCharIdentifier()));
periodicDamage = Math.round(periodicDamage * modTable.get(victim.getCharIdentifier()));
// overtime damage
victim.setOverTimeDamage(periodicDamage);
victim.setOverTimeRounds(HeroConstants.IGNITE_OVERTIME_ROUNDS);
return totalDamage;
}
@Override
public void applyStrategy() {
StrategySelector.selectStrategy(this);
if (getAppliedStrategy() != null) {
getAppliedStrategy().algorithm(this);
}
}
@Override
public int acceptDamage(final VisitorHero v) {
return v.giveDamage(this);
}
@Override
public int giveDamage(final Pyromancer pyromancer) {
return this.firstAbility(pyromancer)
+ this.secondAbility(pyromancer);
}
@Override
public int giveDamage(final Knight knight) {
return this.firstAbility(knight)
+ this.secondAbility(knight);
}
@Override
public int giveDamage(final Rogue rogue) {
return this.firstAbility(rogue)
+ this.secondAbility(rogue);
}
@Override
public int giveDamage(final Wizard wizard) {
return this.firstAbility(wizard)
+ this.secondAbility(wizard);
}
@Override
public void acceptAngelAbility(final AbstractAngel angel) {
angel.applyAngelAbility(this);
}
}

View File

@ -0,0 +1,26 @@
package hero;
import java.util.HashMap;
import java.util.Map;
final class RaceModifierTable {
static Map<Character, Float> getTable(final float rogueMod, final float knightMod,
final float pyromancerMod, final float wizardMod,
final AbstractHero hero) {
final Map<Character, Float> table = new HashMap<>();
table.put('R', rogueMod + (rogueMod != 1 ? hero.getAngelMod() : 0)
+ (rogueMod != 1 ? hero.getStrategyMod() : 0));
table.put('K', knightMod + (knightMod != 1 ? hero.getAngelMod() : 0)
+ (knightMod != 1 ? hero.getStrategyMod() : 0));
table.put('P', pyromancerMod + (pyromancerMod != 1 ? hero.getAngelMod() : 0)
+ (pyromancerMod != 1 ? hero.getStrategyMod() : 0));
table.put('W', wizardMod + (wizardMod != 1 ? hero.getAngelMod() : 0)
+ (pyromancerMod != 1 ? hero.getStrategyMod() : 0));
return table;
}
}

View File

@ -0,0 +1,149 @@
package hero;
import angel.AbstractAngel;
import strategies.RogueDecreaseHpIncreaseMod;
import strategies.RogueIncreaseHpDecreaseMod;
import strategies.StrategySelector;
import java.util.Map;
public final class Rogue extends AbstractHero {
private int multipleHitDamage;
public Rogue(final int hp, final int xp, final int posX, final int posY, final int level,
final int levelBonusHp, final Character terrain, final float terrainBonus,
final Character identifier, final int numberIdentifier) {
super(hp, xp, posX, posY, level, levelBonusHp, terrain, terrainBonus,
identifier, numberIdentifier);
multipleHitDamage = 0;
addStrategy(new RogueDecreaseHpIncreaseMod());
addStrategy(new RogueIncreaseHpDecreaseMod());
}
// backstab
@Override
public int firstAbility(final AbstractHero victim) {
int baseDamage = HeroConstants.BACKSTAB_BASE_DAMAGE;
int levelBonusDamage = this.getLevel() * HeroConstants.BACKSTAB_LVLBONUS_DAMAGE;
// base damage
float totalDamageFloat = baseDamage + levelBonusDamage;
// critical damage
if (this.multipleHitDamage % HeroConstants.CRITICAL_HIT_CYCLE == 0
&& this.getCurrentTerrain() == this.getSpecialTerrain()) {
totalDamageFloat = totalDamageFloat * HeroConstants.CRITICAL_HIT_BONUS;
}
this.multipleHitDamage++;
// land bonus
if (this.getCurrentTerrain() == this.getSpecialTerrain()) {
totalDamageFloat = totalDamageFloat * this.getTerrainBonus();
}
// rounded after land bonus was applied
int totalDamage = Math.round(totalDamageFloat);
// damage without race mod
this.setTotalDamageWithoutRaceMod(totalDamage);
// race mod
Map<Character, Float> modTable = RaceModifierTable.getTable(
HeroConstants.BACKSTAB_ROGUE_MOD,
HeroConstants.BACKSTAB_KNIGHT_MOD,
HeroConstants.BACKSTAB_PYROMANCER_MOD,
HeroConstants.BACKSTAB_WIZARD_MOD, this);
totalDamage = Math.round(totalDamage * modTable.get(victim.getCharIdentifier()));
return totalDamage;
}
// paralysis
@Override
public int secondAbility(final AbstractHero victim) {
int baseDamage = HeroConstants.PARALYSIS_BASE_DAMAGE;
int levelBonusDamage = this.getLevel() * HeroConstants.PARALYSIS_LVLBONUS_DAMAGE;
// base damage
float totalDamageFloat = baseDamage + levelBonusDamage;
// land bonus
if (this.getCurrentTerrain() == this.getSpecialTerrain()) {
totalDamageFloat = totalDamageFloat * this.getTerrainBonus();
}
int totalDamage = Math.round(totalDamageFloat);
// damage without race mod
this.setTotalDamageWithoutRaceMod(totalDamage
+ this.getTotalDamageWithoutRaceMod());
// race mod
Map<Character, Float> modTable = RaceModifierTable.getTable(
HeroConstants.PARALYSIS_ROGUE_MOD,
HeroConstants.PARALYSIS_KNIGHT_MOD,
HeroConstants.PARALYSIS_PYROMANCER_MOD,
HeroConstants.PARALYSIS_WIZARD_MOD, this);
totalDamage = Math.round(totalDamageFloat * modTable.get(victim.getCharIdentifier()));
// overtime damage and frozen
victim.setOverTimeDamage(totalDamage);
victim.setFrozen(true);
if (this.getCurrentTerrain() == 'W' && victim.getCurrentTerrain() == 'W') {
victim.setOverTimeRounds(HeroConstants.PARALYSIS_EXTENDED_OVERTIME_ROUNDS);
victim.setFrozenTime(HeroConstants.PARALYSIS_EXTENDED_OVERTIME_ROUNDS);
} else {
victim.setOverTimeRounds(HeroConstants.PARALYSIS_NORMAL_OVERTIME_ROUNDS);
victim.setFrozenTime(HeroConstants.PARALYSIS_NORMAL_OVERTIME_ROUNDS);
}
return totalDamage;
}
@Override
public void applyStrategy() {
StrategySelector.selectStrategy(this);
if (getAppliedStrategy() != null) {
getAppliedStrategy().algorithm(this);
}
}
@Override
public int acceptDamage(final VisitorHero v) {
return v.giveDamage(this);
}
@Override
public int giveDamage(final Pyromancer pyromancer) {
return this.firstAbility(pyromancer)
+ this.secondAbility(pyromancer);
}
@Override
public int giveDamage(final Knight knight) {
return this.firstAbility(knight)
+ this.secondAbility(knight);
}
@Override
public int giveDamage(final Rogue rogue) {
return this.firstAbility(rogue)
+ this.secondAbility(rogue);
}
@Override
public int giveDamage(final Wizard wizard) {
return this.firstAbility(wizard)
+ this.secondAbility(wizard);
}
@Override
public void acceptAngelAbility(final AbstractAngel angel) {
angel.applyAngelAbility(this);
}
}

View File

@ -0,0 +1,5 @@
package hero;
public interface VisitableHero {
int acceptDamage(VisitorHero v);
}

View File

@ -0,0 +1,8 @@
package hero;
public interface VisitorHero {
int giveDamage(Pyromancer pyromancer);
int giveDamage(Knight knight);
int giveDamage(Rogue rogue);
int giveDamage(Wizard wizard);
}

View File

@ -0,0 +1,134 @@
package hero;
import angel.AbstractAngel;
import strategies.StrategySelector;
import strategies.WizardDecreaseHpIncreaseMod;
import strategies.WizardIncreaseHpDecreaseMod;
import java.util.Map;
public final class Wizard extends AbstractHero {
public Wizard(final int hp, final int xp, final int posX, final int posY, final int level,
final int levelBonusHp, final Character terrain, final float terrainBonus,
final Character identifier, final int numberIdentifier) {
super(hp, xp, posX, posY, level, levelBonusHp, terrain, terrainBonus,
identifier, numberIdentifier);
addStrategy(new WizardDecreaseHpIncreaseMod());
addStrategy(new WizardIncreaseHpDecreaseMod());
}
// drain
@Override
public int firstAbility(final AbstractHero victim) {
final float damagePercent = HeroConstants.DRAIN_BASE_DAMAGE;
final float levelBonusPercent = HeroConstants.DRAIN_LVLBONUS_DAMAGE;
// base percent
float totalPercent = damagePercent + levelBonusPercent * this.getLevel();
// land bonus
if (this.getCurrentTerrain() == this.getSpecialTerrain()) {
totalPercent = totalPercent * this.getTerrainBonus();
}
// race mod
Map<Character, Float> modTable = RaceModifierTable.getTable(
HeroConstants.DRAIN_ROGUE_MOD,
HeroConstants.DRAIN_KNIGHT_MOD,
HeroConstants.DRAIN_PYROMANCER_MOD,
HeroConstants.DRAIN_WIZARD_MOD, this
);
totalPercent = totalPercent * modTable.get(victim.getCharIdentifier());
int victimMaxLevelHp = victim.getMaxHp() + victim.getLevelBonusHp()
* victim.getLevel();
// percent * min(0.3*max_hp, curr_hp)
int totalDamage = Math.round(totalPercent * Math.min(
HeroConstants.DRAIN_MAX_HP_PERCENT * victimMaxLevelHp, victim.getHp()));
return totalDamage;
}
// deflect
@Override
public int secondAbility(final AbstractHero victim) {
final float damagePercent = HeroConstants.DEFLECT_BASE_DAMAGE;
final float levelBonusPercent = HeroConstants.DEFLECT_LVLBONUS_DAMAGE;
// base percent
float totalPercent = damagePercent + levelBonusPercent * this.getLevel();
if (totalPercent > HeroConstants.DEFLECT_MAX_BONUS_PERCENT) {
totalPercent = HeroConstants.DEFLECT_MAX_BONUS_PERCENT;
}
// land bonus
if (this.getCurrentTerrain() == this.getSpecialTerrain()) {
totalPercent = totalPercent * this.getTerrainBonus();
}
// race mod
Map<Character, Float> modTable = RaceModifierTable.getTable(
HeroConstants.DEFLECT_ROGUE_MOD,
HeroConstants.DEFLECT_KNIGHT_MOD,
HeroConstants.DEFLECT_PYROMANCER_MOD,
HeroConstants.DEFLECT_WIZARD_MOD, this
);
totalPercent = totalPercent * modTable.get(victim.getCharIdentifier());
// total damage without race modifiers
int victimDamage = victim.getTotalDamageWithoutRaceMod();
int totalDamage = Math.round(victimDamage * totalPercent);
return totalDamage;
}
@Override
public void applyStrategy() {
StrategySelector.selectStrategy(this);
if (getAppliedStrategy() != null) {
getAppliedStrategy().algorithm(this);
}
}
@Override
public int acceptDamage(final VisitorHero v) {
return v.giveDamage(this);
}
@Override
public int giveDamage(final Pyromancer pyromancer) {
return this.firstAbility(pyromancer)
+ this.secondAbility(pyromancer);
}
@Override
public int giveDamage(final Knight knight) {
return this.firstAbility(knight)
+ this.secondAbility(knight);
}
@Override
public int giveDamage(final Rogue rogue) {
return this.firstAbility(rogue)
+ this.secondAbility(rogue);
}
@Override
public int giveDamage(final Wizard wizard) {
return this.firstAbility(wizard)
+ this.secondAbility(wizard);
}
@Override
public void acceptAngelAbility(final AbstractAngel angel) {
angel.applyAngelAbility(this);
}
}

View File

@ -0,0 +1,55 @@
package main;
import map.TerrainMap;
import java.util.List;
public final class GameInput {
private final List<List<Character>> map;
private final int heroesNo;
private final List<String> heroes;
private int roundsNo;
private final List<String> rounds;
private final List<String> angels;
GameInput(final int matrixLines, final int matrixCols, final List<String> lands,
final int heroesNo, final List<String> heroes, final int roundsNo,
final List<String> rounds, final List<String> angels) {
this.map = TerrainMap.getTerrainMap(matrixLines, matrixCols, lands);
this.heroesNo = heroesNo;
this.heroes = heroes;
this.roundsNo = roundsNo;
this.rounds = rounds;
this.angels = angels;
}
public List<List<Character>> getMap() {
return map;
}
public int getHeroesNo() {
return heroesNo;
}
public List<String> getHeroes() {
return heroes;
}
public int getRoundsNo() {
return roundsNo;
}
public List<String> getRounds() {
return rounds;
}
public List<String> getAngels() {
return angels;
}
}

View File

@ -0,0 +1,99 @@
package main;
import fileio.FileSystem;
import utils.Utils;
import java.util.ArrayList;
import java.util.List;
final class GameInputLoader {
private final String mInputPath;
private final String mOutputPath;
GameInputLoader(final String inputPath, final String outputPath) {
this.mInputPath = inputPath;
this.mOutputPath = outputPath;
}
GameInput load() {
int mMatrixLines = 0;
int mMatrixCols = 0;
List<String> lineLands = new ArrayList<>();
int heroesNo = 0;
List<StringBuilder> lineHeroes = new ArrayList<>();
int roundsNo = 0;
List<String> lineRounds = new ArrayList<>();
List<String> lineAngels = new ArrayList<>();
try {
final FileSystem fs = new FileSystem(mInputPath, mOutputPath);
// first line
mMatrixLines = fs.nextInt();
mMatrixCols = fs.nextInt();
// next mMatrixLines lines
for (int i = 0; i < mMatrixLines; i++) {
lineLands.add(fs.nextWord());
}
// heroes number line
heroesNo = fs.nextInt();
// next heroesNo lines
for (int i = 0; i < heroesNo; i++) {
lineHeroes.add(new StringBuilder());
for (int j = 0; j < 3; j++) {
lineHeroes.get(i).append(fs.nextWord() + " ");
}
}
// rounds number line
roundsNo = fs.nextInt();
// next roundsNo lines reading rounds info
for (int i = 0; i < roundsNo; i++) {
lineRounds.add(fs.nextWord());
}
// next roundsNo lines reading angel info
for (int i = 0; i < roundsNo; i++) {
// read the first number from a line
int angelPerRound = fs.nextInt();
StringBuilder round = new StringBuilder();
// read the angels
for (int j = 0; j < angelPerRound; j++) {
round.append(fs.nextWord() + " ");
}
lineAngels.add(i, round.toString());
}
fs.close();
} catch (final Exception e) {
e.printStackTrace();
}
assert mMatrixLines != 0 : "Error reading number of lines";
assert mMatrixCols != 0 : "Error reading number of columns";
assert lineLands.size() != 0 : "Error reading lands";
assert heroesNo != 0 : "Error reading number of heroes";
assert lineHeroes.size() != 0 : "Error reading heroes stats";
assert roundsNo != 0 : "Error reading number of rounds";
assert lineRounds.size() != 0 : "Error reading rounds stats";
return new GameInput(mMatrixLines, mMatrixCols, lineLands,
heroesNo, Utils.strBuilderArrToStrArr(lineHeroes), roundsNo,
lineRounds, lineAngels);
}
}

View File

@ -0,0 +1,147 @@
package main;
import fileio.FileSystem;
import hero.AbstractHero;
import java.io.IOException;
import java.util.List;
public final class GameOutput {
private final String mInputPath;
private final String mOutputPath;
private FileSystem fs;
public GameOutput(final String inputPath, final String outputPath) {
this.mInputPath = inputPath;
this.mOutputPath = outputPath;
try {
fs = new FileSystem(mInputPath, mOutputPath);
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeDeadPlayer(AbstractHero killedHero, AbstractHero killerHero,
String killedHeroName, String killerHeroName) {
try {
String output = "Player " + killedHeroName + " " + killedHero.getNumberIdentifier()
+ " was killed by " + killerHeroName + " " + killerHero.getNumberIdentifier();
fs.writeWord(output);
fs.writeNewLine();
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeLevelUp(String heroName, int numberIdentifier, int level) {
try {
String output = heroName + " " + numberIdentifier + " reached level " + level;
fs.writeWord(output);
fs.writeNewLine();
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeAngelAbility(String angelName, String action, String heroName, int numberIdentifier) {
try {
String output = angelName + " " + action + " " + heroName + " " + numberIdentifier;
fs.writeWord(output);
fs.writeNewLine();
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeSpawnedAngel(String angelName, int posX, int posY) {
try {
String output = "Angel " + angelName + " was spawned at " + posX + " " + posY;
fs.writeWord(output);
fs.writeNewLine();
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeRoundNumber(int roundNumber) {
try {
String output = "~~ Round " + roundNumber + " ~~";
if (roundNumber != 1) {
fs.writeNewLine();
}
fs.writeWord(output);
fs.writeNewLine();
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeLifeStateHero(AbstractHero hero, String heroName) {
try {
int numberIdentifier = hero.getNumberIdentifier();
String output = null;
if (hero.isAlive()) {
output = "Player " + heroName + " " + numberIdentifier + " was brought to life"
+ " by an angel";
} else {
output = "Player " + heroName + " " + numberIdentifier + " was killed"
+ " by an angel";
}
fs.writeWord(output);
fs.writeNewLine();
} catch (IOException e) {
e.printStackTrace();
}
}
void writeFinalResults(final List<AbstractHero> heroList) {
try {
fs.writeNewLine();
fs.writeWord("~~ Results ~~");
fs.writeNewLine();
for (AbstractHero hero : heroList) {
if (hero.getHp() == 0) {
// identifier
fs.writeCharacter(hero.getCharIdentifier());
fs.writeCharacter(' ');
// dead
fs.writeWord("dead");
fs.writeNewLine();
} else {
// identifier
fs.writeCharacter(hero.getCharIdentifier());
fs.writeCharacter(' ');
// level
fs.writeInt(hero.getLevel());
fs.writeCharacter(' ');
// xp
fs.writeInt(hero.getXp());
fs.writeCharacter(' ');
// hp
fs.writeInt(hero.getHp());
fs.writeCharacter(' ');
// x position
fs.writeInt(hero.getPosX());
fs.writeCharacter(' ');
// y position
fs.writeInt(hero.getPosY());
fs.writeNewLine();
}
}
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,27 @@
package main;
import engine.GameEngine;
import hero.AbstractHero;
import java.util.List;
public final class Main {
public static GameOutput gameOutput;
public static void main(final String[] args) {
try {
GameInputLoader inputLoader = new GameInputLoader(args[0], args[1]);
GameInput input = inputLoader.load();
GameOutput gameOutput = new GameOutput(args[0], args[1]);
Main.gameOutput = gameOutput;
GameEngine gameEngine = new GameEngine(input);
List<AbstractHero> heroList = gameEngine.play();
gameOutput.writeFinalResults(heroList);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,34 @@
package map;
import java.util.ArrayList;
import java.util.List;
public final class TerrainMap {
private static TerrainMap instance = null;
private List<List<Character>> map;
private TerrainMap(final int lines, final int cols, final List<String> lands) {
map = new ArrayList<>();
// initialize the matrix
for (int i = 0; i < lines; i++) {
map.add(new ArrayList<>());
}
for (int i = 0; i < lines; i++) {
for (int j = 0; j < cols; j++) {
map.get(i).add(lands.get(i).charAt(j));
}
}
}
public static List<List<Character>> getTerrainMap(final int lines, final int cols,
final List<String> lands) {
if (instance == null) {
instance = new TerrainMap(lines, cols, lands);
}
return instance.map;
}
}

View File

@ -0,0 +1,7 @@
package strategies;
import hero.AbstractHero;
public interface AbstractStrategy {
void algorithm(AbstractHero hero);
}

View File

@ -0,0 +1,15 @@
package strategies;
import hero.AbstractHero;
public class KnightDecreaseHpIncreaseMod implements AbstractStrategy{
@Override
public void algorithm(final AbstractHero hero) {
int currentHp = hero.getHp();
int newHp = (int) (currentHp * StrategyConstants.KNIGHT_DECREASE_HP);
hero.setHp(newHp);
hero.setStrategyMod(StrategyConstants.KNIGHT_INCREASE_MOD);
}
}

View File

@ -0,0 +1,15 @@
package strategies;
import hero.AbstractHero;
public class KnightIncreaseHpDecreaseMod implements AbstractStrategy {
@Override
public void algorithm(final AbstractHero hero) {
int currentHp = hero.getHp();
int newHp = (int) (currentHp * StrategyConstants.KNIGHT_INCREASE_HP);
hero.setHp(newHp);
hero.setStrategyMod(StrategyConstants.KNIGHT_DECREASE_MOD);
}
}

View File

@ -0,0 +1,16 @@
package strategies;
import hero.AbstractHero;
public class PyroDecreaseHpIncreaseMod implements AbstractStrategy {
@Override
public void algorithm(final AbstractHero hero) {
int currentHp = hero.getHp();
int newHp = (int) (currentHp * StrategyConstants.PYRO_DECREASE_HP);
hero.setHp(newHp);
hero.setStrategyMod(StrategyConstants.PYRO_INCREASE_MOD);
}
}

View File

@ -0,0 +1,15 @@
package strategies;
import hero.AbstractHero;
public class PyroIncreaseHpDecreaseMod implements AbstractStrategy {
@Override
public void algorithm(final AbstractHero hero) {
int currentHp = hero.getHp();
int newHp = (int) (currentHp * StrategyConstants.PYRO_INCREASE_HP);
hero.setHp(newHp);
hero.setStrategyMod(StrategyConstants.PYRO_DECREASE_MOD);
}
}

View File

@ -0,0 +1,15 @@
package strategies;
import hero.AbstractHero;
public class RogueDecreaseHpIncreaseMod implements AbstractStrategy{
@Override
public void algorithm(AbstractHero hero) {
int currentHp = hero.getHp();
int newHp = (int) (currentHp * StrategyConstants.ROGUE_DECREASE_HP);
hero.setHp(newHp);
hero.setStrategyMod(StrategyConstants.ROGUE_INCREASE_MOD);
}
}

View File

@ -0,0 +1,15 @@
package strategies;
import hero.AbstractHero;
public class RogueIncreaseHpDecreaseMod implements AbstractStrategy {
@Override
public void algorithm(AbstractHero hero) {
int currentHp = hero.getHp();
int newHp = (int) (currentHp * StrategyConstants.ROGUE_INCREASE_HP);
hero.setHp(newHp);
hero.setStrategyMod(StrategyConstants.ROGUE_DECREASE_MOD);
}
}

View File

@ -0,0 +1,43 @@
package strategies;
public class StrategyConstants {
// --> Knight constants
public static float KNIGHT_DECREASE_HP = 0.80f;
public static float KNIGHT_INCREASE_MOD = 0.50f;
public static float KNIGHT_INCREASE_HP = 1.25f;
public static float KNIGHT_DECREASE_MOD = -0.20f;
public static float KNIGHT_LOWER_LIMIT = 1/3f;
public static float KNIGHT_UPPER_LIMIT = 1/2f;
// --> Pyro constants
public static float PYRO_DECREASE_HP = 0.75f;
public static float PYRO_INCREASE_MOD = 0.70f;
public static float PYRO_INCREASE_HP = 1.33f;
public static float PYRO_DECREASE_MOD = -0.30f;
public static float PYRO_LOWER_LIMIT = 1/4f;
public static float PYRO_UPPER_LIMIT = 1/3f;
// --> Rogue constants
public static float ROGUE_DECREASE_HP = (1-1/7f);
public static float ROGUE_INCREASE_MOD = 0.40f;
public static float ROGUE_INCREASE_HP = 1.50f;
public static float ROGUE_DECREASE_MOD = -0.10f;
public static float ROGUE_LOWER_LIMIT = 1/7f;
public static float ROGUE_UPPER_LIMIT = 1/5f;
// --> Wizard constants
public static float WIZARD_DECREASE_HP = (1-1/10f);
public static float WIZARD_INCREASE_MOD = 0.60f;
public static float WIZARD_INCREASE_HP = 1.20f;
public static float WIZARD_DECREASE_MOD = -0.20f;
public static float WIZARD_LOWER_LIMIT = 1/4f;
public static float WIZARD_UPPER_LIMIT = 1/2f;
}

View File

@ -0,0 +1,47 @@
package strategies;
import hero.AbstractHero;
public class StrategySelector {
public static void selectStrategy(final AbstractHero hero) {
float lower_limit = 0;
float upper_limit = 0;
switch (hero.getCharIdentifier()) {
case 'K' :
lower_limit = StrategyConstants.KNIGHT_LOWER_LIMIT;
upper_limit = StrategyConstants.KNIGHT_UPPER_LIMIT;
break;
case 'P' :
lower_limit = StrategyConstants.PYRO_LOWER_LIMIT;
upper_limit = StrategyConstants.PYRO_UPPER_LIMIT;
break;
case 'R' :
lower_limit = StrategyConstants.ROGUE_LOWER_LIMIT;
upper_limit = StrategyConstants.ROGUE_UPPER_LIMIT;
break;
case 'W' :
lower_limit = StrategyConstants.WIZARD_LOWER_LIMIT;
upper_limit = StrategyConstants.WIZARD_UPPER_LIMIT;
break;
}
float max_level_hp = hero.getMaxHp() + hero.getLevel() * hero.getLevelBonusHp();
if (lower_limit * max_level_hp < (float)hero.getHp()
&& (float)hero.getHp() < upper_limit * max_level_hp) {
hero.setAppliedStrategy(hero.getStrategies().get(0));
return;
}
if ((float)hero.getHp() < lower_limit * max_level_hp) {
hero.setAppliedStrategy(hero.getStrategies().get(1));
return;
}
// default case where none of the strategies was chosen
hero.setAppliedStrategy(null);
}
}

View File

@ -0,0 +1,15 @@
package strategies;
import hero.AbstractHero;
public class WizardDecreaseHpIncreaseMod implements AbstractStrategy {
@Override
public void algorithm(AbstractHero hero) {
int currentHp = hero.getHp();
int newHp = (int) (currentHp * StrategyConstants.WIZARD_DECREASE_HP);
hero.setHp(newHp);
hero.setStrategyMod(StrategyConstants.WIZARD_INCREASE_MOD);
}
}

View File

@ -0,0 +1,15 @@
package strategies;
import hero.AbstractHero;
public class WizardIncreaseHpDecreaseMod implements AbstractStrategy {
@Override
public void algorithm(AbstractHero hero) {
int currentHp = hero.getHp();
int newHp = (int) (currentHp * StrategyConstants.WIZARD_INCREASE_HP);
hero.setHp(newHp);
hero.setStrategyMod(StrategyConstants.WIZARD_DECREASE_MOD);
}
}

View File

@ -0,0 +1,41 @@
package utils;
import angel.AbstractAngel;
import angel.AngelsFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public final class Utils {
public static List<String> strBuilderArrToStrArr(final List<StringBuilder> array) {
List<String> stringArray = new ArrayList<>();
for (StringBuilder stringBuilder : array) {
stringArray.add(stringBuilder.toString());
}
return stringArray;
}
public static List<AbstractAngel> strListToAbstrAngelList(final String angels) {
List<AbstractAngel> abstractAngels = new ArrayList<>();
List<String> angelsList = Arrays.asList(angels.split(" "));
AngelsFactory factory = AngelsFactory.getInstance();
for (int i = 0; i < angelsList.size(); i++) {
List<String> angelInfo = Arrays.asList(angelsList.get(i).split(","));
if (angelInfo.size() == 1) {
continue;
}
String name = angelInfo.get(0);
int posX = Integer.parseInt(angelInfo.get(1));
int posY = Integer.parseInt(angelInfo.get(2));
abstractAngels.add(factory.getAngel(name, posX, posY));
}
return abstractAngels;
}
}