Skip to content

Commit

Permalink
More balances (#64)
Browse files Browse the repository at this point in the history
* Boss stats and RESI Battles

Made it so that if any enemy has "R.E.S.I." in their name, their element will always change after being attacked. Fixed boss stats after updating their levels

* QOL

Some quality of life changes and fixed bosses since they were too easy

* Level cap

Added level cap and flavor text

* XP cap

Changed xp cap. I think 4500 is a good number, so I hope to not change it again

* Anahita changes

She's too strong, so her ranged attack was decreased and ranged defense increased. It might slow down her massive ranged attack yield in the endgame

* Cheer skill buff

Made it so that cheer skills are activated instantly after cheer partners are assigned. Due to this, enemy stats were also buffed

* Update Game.java

Removed the code added for testing
  • Loading branch information
KingPhilip14 authored Jan 10, 2024
1 parent 0223c74 commit 1b0a6c9
Show file tree
Hide file tree
Showing 17 changed files with 280 additions and 251 deletions.
21 changes: 10 additions & 11 deletions ReadMe.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
# Project Perfection

## What is this project?
This is a text-based RPG I started as a freshman in college to practice some of the coding concepts I learned in class. As of September 2023, it isn't complete yet, but it is nearly finished.

-----
This is a text-based RPG I started as a freshman in college to practice some of the coding concepts I learned in class. As of September 2023, it isn't complete yet, but it is nearly finished.

## What can you do in the game?
* The Battle System
* This game has a turn-based combat system, similar to Pokemon. This allows players to use the given characters to fight in battles against enemies by using unique attacks. Attacks can deal damage, apply a buff or debuff to a stat, or heal an ally.
* The Game World
* There are NPCs the player can talk to and potentially receive gifts from. These characters help make the game feel more alive and diverse. As players progress through the story, if they've been in certain areas, they might see what NPCs they can talk to either disappear or have new dialogue depending on the state of the world.
* There are ~17 unique locations the player can explore. The locations affect the types of enemies encountered and their levels.
* The Shop
* There is also a shop system implemented in the game. Whenever the player wins or loses a battle, they will either receive or lose gold. That gold can be used to purchase items from the shops located in the various town locations.
* Each town has a different list of items it sells. For example, the items sold in the first town you visit will not be the exact same in any of the other towns.

-----
- The Battle System
- This game has a turn-based combat system, similar to Pokemon. This allows players to use the given characters to fight in battles against enemies by using unique attacks. Attacks can deal damage, apply a buff or debuff to a stat, or heal an ally.
- The Game World
- There are NPCs the player can talk to and potentially receive gifts from. These characters help make the game feel more alive and diverse. As players progress through the story, if they've been in certain areas, they might see what NPCs they can talk to either disappear or have new dialogue depending on the state of the world.
- There are ~17 unique locations the player can explore. The locations affect the types of enemies encountered and their levels.
- The Shop
- There is also a shop system implemented in the game. Whenever the player wins or loses a battle, they will either receive or lose gold. That gold can be used to purchase items from the shops located in the various town locations.
- Each town has a different list of items it sells. For example, the items sold in the first town you visit will not be the exact same in any of the other towns.

## What have I learned while working on this?

I know and understand that a lot of systems I have in place are not the best, nor that the project as a whole is organized in the best way. I have worked on other projects for NDSU's ACM chapter, which has helped me understand better coding structures and organizations. When this project is done, I plan to revisit this text-based system and make a framework. That framework will allow me to optimize the game and create more in the future if I so desire.
4 changes: 2 additions & 2 deletions src/Battle/Attack.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ public String getNameWithAttackType()
}
else if(this instanceof BuffAttack)
{
result += "(Buff Attack)";
result += "(Buff)";
}
else if(this instanceof DebuffAttack)
{
result += "(Debuff Attack)";
result += "(Debuff)";
}
else if(this instanceof SingleHealingAttack)
{
Expand Down
156 changes: 89 additions & 67 deletions src/Battle/Battle.java
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ private void addPlayerToCheer(int response, Player player)
player.setCheerPartner(cheer);
cheer.setPlayerToCheer(player);
cheer.printCheerReadyMessage();

activateCheerAbility(player.getCheerPartner());
}

private String addPositionMessage(String message)
Expand Down Expand Up @@ -643,10 +645,10 @@ private void activatePlayerTurn(Player player)
}
}

if(!player.isDead())
{
activateCheerPartner(player);
}
// if(!player.isDead())
// {
// activateCheerPartner(player);
// }
}

/**
Expand All @@ -670,71 +672,75 @@ private void forfeit(Player player)
}
}

private void activateCheerPartner(Player player)
{
if((!(enemyTeam.isEmpty())) && (player.getCheerPartner() != null))
{
Player cheer = player.getCheerPartner();
activateCheerAbility(cheer);
}
}
// private void activateCheerPartner(Player player)
// {
// if((!(enemyTeam.isEmpty())) && (player.getCheerPartner() != null))
// {
// Player cheer = player.getCheerPartner();
// activateCheerAbility(cheer);
// }
// }

/**
* After a cheer partner is assigned, they will increase a repsective stat to the character they're cheering
* @param cheer
*/
private void activateCheerAbility(Player cheer)
{
Random rand = new Random();
int chance = rand.nextInt(20);

if(chance == 0)
{
PlayerClass pc = cheer.getPlayerClass();
Player playerToCheer = cheer.getPlayerToCheer();
MainGame.printlnln(cheer.getName() + "'s cheer skill was activiated!");

switch (pc.getPrimaryRole())
{
case "Clerk":
if(!playerToCheer.isHealthy())
{
int amt = (int)(playerToCheer.getMaxHealth() * Stat.get_cheer_buff_value());
playerToCheer.setCurrentHealth(amt);
MainGame.printlnln(cheer.getName() + " healed " + playerToCheer.getName() + " " + amt + " HP!");
}
else
{
MainGame.printlnln("But " + cheer.getName() + " couldn't do anything!");
MainGame.printlnln(cheer.getName() + ": Sorry about that!");
}
break;
case "Tank":
Stat defense = playerToCheer.getDefense();
// playerToCheer.setDefense((int)Math.round(defense.getValue() * Stat.get_cheer_buff_value()));
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s defense by 20%!");
defense.increaseCheerBuff(Stat.get_cheer_buff_value());
defense = playerToCheer.getRangedDefense();
// playerToCheer.setRangedDefense((int)Math.round(defense.getValue() * Stat.get_cheer_buff_value()));
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s ranged defense by 20%!");
defense.increaseCheerBuff(Stat.get_cheer_buff_value());
break;
case "Striker":
Stat attack = playerToCheer.getAttack();
// playerToCheer.setAttack((int)Math.round(attack.getValue() * Stat.get_cheer_buff_value()));
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s attack by 20%!");
attack.increaseCheerBuff(Stat.get_cheer_buff_value());
attack = playerToCheer.getRangedAttack();
// playerToCheer.setRangedAttack((int)Math.round(attack.getValue() * Stat.get_cheer_buff_value()));
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s ranged attack by 20%!");
attack.increaseCheerBuff(Stat.get_cheer_buff_value());
break;
default:
Stat speed = playerToCheer.getSpeed();
// playerToCheer.setSpeed((int)Math.round(speed.getValue() * Stat.get_cheer_buff_value()));
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s speed by 20%!");
speed.increaseCheerBuff(Stat.get_cheer_buff_value());
break;
}
{
PlayerClass pc = cheer.getPlayerClass();
Player playerToCheer = cheer.getPlayerToCheer();

MainGame.printlnln(cheer.getName() + "'s cheer skill was activiated!");

int before = 0;

switch (pc.getPrimaryRole())
{
case "Clerk":
int amt = (int)(playerToCheer.getMaxHealth() * 0.25);
before = playerToCheer.getCurrentHealth();
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s' HP by " + amt + "!");
playerToCheer.setCurrentHealth(playerToCheer.getCurrentHealth() + amt);
MainGame.printlnln(playerToCheer.getName() + "'s health change: " + before + " ---> " + playerToCheer.getCurrentHealth());
break;
case "Tank":
Stat defense = playerToCheer.getDefense();
defense.setCheerBuffModifier(1.2);
before = defense.getValue();
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s defense by 20%!");
defense.applyCheerBuff();
MainGame.printlnln(playerToCheer.getName() + "'s Defense change: " + before + " ---> " + defense.getValue());

defense = playerToCheer.getRangedDefense();
defense.setCheerBuffModifier(1.2);
before = defense.getValue();
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s ranged defense by 20%!");
defense.applyCheerBuff();
MainGame.printlnln(playerToCheer.getName() + "'s Ranged Defense change: " + before + " ---> " + defense.getValue());
break;
case "Striker":
Stat attack = playerToCheer.getAttack();
attack.setCheerBuffModifier(1.2);
before = attack.getValue();
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s attack by 20%!");
attack.applyCheerBuff();
MainGame.printlnln(playerToCheer.getName() + "'s Attack change: " + before + " ---> " + attack.getValue());

attack = playerToCheer.getRangedAttack();
attack.setCheerBuffModifier(1.2);
before = attack.getValue();
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s ranged attack by 20%!");
attack.applyCheerBuff();
MainGame.printlnln(playerToCheer.getName() + "'s Ranged Attack change: " + before + " ---> " + attack.getValue());
break;
default:
Stat speed = playerToCheer.getSpeed();
speed.setCheerBuffModifier(1.3);
before = speed.getValue();
MainGame.printlnln(cheer.getName() + " increased " + playerToCheer.getName() + "'s speed by 30%!");
speed.applyCheerBuff();
MainGame.printlnln(playerToCheer.getName() + "'s Speed change: " + before + " ---> " + speed.getValue());
break;
}
}

Expand Down Expand Up @@ -965,6 +971,22 @@ else if(attack instanceof ComboAttack)
player.increaseXP(player, ORIGINAL_PLAYER_POSITIONS, target);
}
}

// Change target's element if it's a R.E.S.I.
if(target.getName().contains("R.E.S.I.") && attack.getAttackHit() && !target.isDead() &&
!player.getElement().equals(target.getElement()))
{
if(attack.getAttackHit() && !target.isDead() && !player.getElement().equals(target.getElement()))
{
RESIEnemy enemy = ((RESIEnemy)target);

enemy.setElement(player.getElement());

MainGame.printlnln(enemy.name + "'s element is now " + enemy.element + "!");

MainGame.promptToEnter();
}
}
}

private void attackWithDebuff(Attack attack, Player player, Enemy target)
Expand Down
2 changes: 1 addition & 1 deletion src/Battle/BossEnemy.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public BossEnemy(String name, String description, String element,
setStats(statValues);
this.element = element;
addElementDescriptor();
xpYield = 45;
xpYield = 65;
}

public void setStatDescription(String desc)
Expand Down
8 changes: 4 additions & 4 deletions src/Battle/Enemy.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public abstract class Enemy extends Character
public Enemy(Wilderness currentLocation)
{
createLevel(currentLocation);
totalStatPoints = level * 65;
totalStatPoints = level * 80;
generateStats();

// RESI enemies will not get their moveset from this classes list of attacks
Expand All @@ -42,7 +42,7 @@ public Enemy(Wilderness currentLocation)
public Enemy(int level)
{
this.level = level;
totalStatPoints = level * 65;
totalStatPoints = level * 80;
generateStats();

// RESI enemies will not get their moveset from this classes list of attacks
Expand All @@ -57,7 +57,7 @@ public Enemy(int level)
public Enemy(Wilderness currentLocation, int level)
{
this.level = level;
totalStatPoints = level * 65;
totalStatPoints = level * 80;
generateStats();

// RESI enemies will not get their moveset from this classes list of attacks
Expand Down Expand Up @@ -89,7 +89,7 @@ public Enemy(String name, String description, int level)
this.name = name;
this.description = description;
this.level = level;
totalStatPoints = level * 65;
totalStatPoints = level * 80;
generateStats();
populateCurrentAttacks();
populateListsOfStats();
Expand Down
24 changes: 19 additions & 5 deletions src/Battle/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ public Player(String name, String description, String element, PlayerClass playe
xpToLevelUp = currentXP;

// Set the xpToLevelUp to not exceed the max
if (xpToLevelUp > 3500)
if (xpToLevelUp > 4200)
{
xpToLevelUp = 3500;
xpToLevelUp = 4200;
}

populateListsOfStats();
Expand Down Expand Up @@ -114,6 +114,8 @@ public void resetStats()
{
for(Stat s : listOfStats)
{
s.resetCheerBuffModifier();

if(s.getValue() != s.getOriginalValue())
{
s.resetValue(this);
Expand Down Expand Up @@ -212,6 +214,13 @@ private void getXPAmount(Player player, int amt)

private void updateXP(int xpAmt)
{
if(level == 35)
{
MainGame.printlnln("You've reached the max level! Congrats!");
MainGame.promptToEnter();
return;
}

if(xpToLevelUp - xpAmt <= 0)
{
int remaining = xpAmt - xpToLevelUp;
Expand Down Expand Up @@ -267,6 +276,7 @@ private void updateXP(int xpAmt)

private void levelUp(int remainingXP)
{

MainGame.printlnln(name + " leveled up to level " + (level + 1) + "!");
MainGame.printlnln("Stats before:");
MainGame.printlnln(toStringOriginalStats());
Expand All @@ -277,9 +287,13 @@ private void levelUp(int remainingXP)
level++;
xpToLevelUp = (int)Math.round((Math.pow((level + 1) * 10, 2)) / 4);

if(xpToLevelUp > 3500) // set a cap for XP gains to not let game progression take too long
if(level == 35)
{
xpToLevelUp = 0; // No more exp can be gained
}
else if(xpToLevelUp > 4500) // set a cap for XP gains to not let game progression take too long
{
xpToLevelUp = 3500;
xpToLevelUp = 4500;
}

updateStats();
Expand Down Expand Up @@ -716,7 +730,7 @@ private void reapplyCheerBuff()
{
for(Stat s : listOfStats)
{
s.reapplyCheerBuff();
s.applyCheerBuff();
}
}

Expand Down
30 changes: 15 additions & 15 deletions src/Battle/RESIBattle.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@ public RESIBattle(ArrayList<Enemy> enemyTeam, ArrayList<Player> playerTeam)
startingText = "A L E R T! Incoming R.E.S.I. Bots!\n\nBattle: S T A R T";
}

@Override
/**
* This overridden method changes the RESI Bot's element depending on the player's element.
*/
protected void attackWithOffense(Attack attack, Player player, Enemy target)
{
super.attackWithOffense(attack, player, target);
// @Override
// /**
// * This overridden method changes the RESI Bot's element depending on the player's element.
// */
// protected void attackWithOffense(Attack attack, Player player, Enemy target)
// {
// super.attackWithOffense(attack, player, target);

if(attack.getAttackHit() && !target.isDead() && !player.getElement().equals(target.getElement()))
{
RESIEnemy enemy = ((RESIEnemy)target);
// if(attack.getAttackHit() && !target.isDead() && !player.getElement().equals(target.getElement()))
// {
// RESIEnemy enemy = ((RESIEnemy)target);

enemy.setElement(player.getElement());
// enemy.setElement(player.getElement());

MainGame.printlnln(enemy.name + "'s element is now " + enemy.element + "!");
// MainGame.printlnln(enemy.name + "'s element is now " + enemy.element + "!");

MainGame.promptToEnter();
}
}
// MainGame.promptToEnter();
// }
// }
}
Loading

0 comments on commit 1b0a6c9

Please sign in to comment.