mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
- Cleanup of combat damage assignment. Fixed a bug with Double Strike.
- Improved the AI handling of trampling creatures.
This commit is contained in:
@@ -2832,6 +2832,31 @@ public class Card extends MyObservable {
|
|||||||
receivedDamageFromThisTurn.clear();
|
receivedDamageFromThisTurn.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//how much damage is enough to kill the creature (for AI)
|
||||||
|
public int getEnoughDamageToKill(int maxDamage, Card source, boolean isCombat) {
|
||||||
|
|
||||||
|
int killDamage = getKillDamage();
|
||||||
|
|
||||||
|
if(getKeyword().contains("Indestructible") || getShield() > 0) {
|
||||||
|
if(!(source.getKeyword().contains("Wither") || source.getKeyword().contains("Infect")))
|
||||||
|
return maxDamage + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(source.getKeyword().contains("Deathtouch")
|
||||||
|
|| source.getKeyword().contains("Whenever CARDNAME deals combat damage to a creature, destroy that creature"))
|
||||||
|
for(int i=1; i < maxDamage+1;i++) {
|
||||||
|
if (predictDamage(i, source, isCombat) > 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=1; i < maxDamage+1;i++) {
|
||||||
|
if (predictDamage(i, source, isCombat) >= killDamage)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxDamage + 1;
|
||||||
|
}
|
||||||
|
|
||||||
//the amount of damage needed to kill the creature (for AI)
|
//the amount of damage needed to kill the creature (for AI)
|
||||||
public int getKillDamage() {
|
public int getKillDamage() {
|
||||||
int killDamage = getLethalDamage() + preventNextDamage;
|
int killDamage = getLethalDamage() + preventNextDamage;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public class Combat {
|
|||||||
private Set<Card> blocked = new HashSet<Card>();
|
private Set<Card> blocked = new HashSet<Card>();
|
||||||
|
|
||||||
private HashMap<Card, CardList> unblockedMap = new HashMap<Card, CardList>();
|
private HashMap<Card, CardList> unblockedMap = new HashMap<Card, CardList>();
|
||||||
private HashMap<Card, Integer> defendingFirstStrikeDamageMap = new HashMap<Card, Integer>();
|
//private HashMap<Card, Integer> defendingFirstStrikeDamageMap = new HashMap<Card, Integer>();
|
||||||
private HashMap<Card, Integer> defendingDamageMap = new HashMap<Card, Integer>();
|
private HashMap<Card, Integer> defendingDamageMap = new HashMap<Card, Integer>();
|
||||||
|
|
||||||
// Defenders are the Defending Player + Each Planeswalker that player controls
|
// Defenders are the Defending Player + Each Planeswalker that player controls
|
||||||
@@ -41,7 +41,7 @@ public class Combat {
|
|||||||
|
|
||||||
attackingDamage = 0;
|
attackingDamage = 0;
|
||||||
defendingDamageMap.clear();
|
defendingDamageMap.clear();
|
||||||
defendingFirstStrikeDamageMap.clear();
|
//defendingFirstStrikeDamageMap.clear();
|
||||||
|
|
||||||
attackingPlayer = null;
|
attackingPlayer = null;
|
||||||
defendingPlayer = null;
|
defendingPlayer = null;
|
||||||
@@ -164,9 +164,11 @@ public class Combat {
|
|||||||
return defendingDamageMap;
|
return defendingDamageMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public HashMap<Card, Integer> getDefendingFirstStrikeDamageMap() {
|
public HashMap<Card, Integer> getDefendingFirstStrikeDamageMap() {
|
||||||
return defendingFirstStrikeDamageMap;
|
return defendingFirstStrikeDamageMap;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public int getTotalDefendingDamage() {
|
public int getTotalDefendingDamage() {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
@@ -180,6 +182,7 @@ public class Combat {
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public int getTotalFirstStrikeDefendingDamage() {
|
public int getTotalFirstStrikeDefendingDamage() {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
|
||||||
@@ -191,6 +194,7 @@ public class Combat {
|
|||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public void setDefendingDamage() {
|
public void setDefendingDamage() {
|
||||||
defendingDamageMap.clear();
|
defendingDamageMap.clear();
|
||||||
@@ -212,6 +216,7 @@ public class Combat {
|
|||||||
}// for
|
}// for
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public void setDefendingFirstStrikeDamage() {
|
public void setDefendingFirstStrikeDamage() {
|
||||||
defendingFirstStrikeDamageMap.clear();
|
defendingFirstStrikeDamageMap.clear();
|
||||||
CardList att = new CardList(getAttackers());
|
CardList att = new CardList(getAttackers());
|
||||||
@@ -231,6 +236,7 @@ public class Combat {
|
|||||||
}
|
}
|
||||||
} // for
|
} // for
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public void addDefendingDamage(int n, Card source) {
|
public void addDefendingDamage(int n, Card source) {
|
||||||
String slot = getDefenderByAttacker(source).toString();
|
String slot = getDefenderByAttacker(source).toString();
|
||||||
@@ -250,6 +256,7 @@ public class Combat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public void addDefendingFirstStrikeDamage(int n, Card source) {
|
public void addDefendingFirstStrikeDamage(int n, Card source) {
|
||||||
String slot = getDefenderByAttacker(source).toString();
|
String slot = getDefenderByAttacker(source).toString();
|
||||||
Object o = defenders.get(Integer.parseInt(slot));
|
Object o = defenders.get(Integer.parseInt(slot));
|
||||||
@@ -268,6 +275,7 @@ public class Combat {
|
|||||||
defendingFirstStrikeDamageMap.get(source) + n);
|
defendingFirstStrikeDamageMap.get(source) + n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public void addAttackingDamage(int n) {
|
public void addAttackingDamage(int n) {
|
||||||
attackingDamage += n;
|
attackingDamage += n;
|
||||||
@@ -388,7 +396,7 @@ public class Combat {
|
|||||||
// also assigns player damage by setPlayerDamage()
|
// also assigns player damage by setPlayerDamage()
|
||||||
public void setAssignedFirstStrikeDamage() {
|
public void setAssignedFirstStrikeDamage() {
|
||||||
|
|
||||||
setDefendingFirstStrikeDamage();
|
//setDefendingFirstStrikeDamage();
|
||||||
|
|
||||||
CardList block;
|
CardList block;
|
||||||
CardList attacking = new CardList(getAttackers());
|
CardList attacking = new CardList(getAttackers());
|
||||||
@@ -396,51 +404,39 @@ public class Combat {
|
|||||||
|
|
||||||
for (int i = 0; i < attacking.size(); i++) {
|
for (int i = 0; i < attacking.size(); i++) {
|
||||||
|
|
||||||
block = getBlockers(attacking.get(i));
|
Card attacker = attacking.get(i);
|
||||||
|
block = getBlockers(attacker);
|
||||||
|
|
||||||
int damageDealt = attacking.get(i).getNetCombatDamage();
|
|
||||||
|
int damageDealt = attacker.getNetCombatDamage();
|
||||||
|
|
||||||
// attacker always gets all blockers' attack
|
// attacker always gets all blockers' attack
|
||||||
|
|
||||||
for (Card b : block) {
|
for (Card b : block) {
|
||||||
if (b.hasFirstStrike() || b.hasDoubleStrike()) {
|
if (b.hasFirstStrike() || b.hasDoubleStrike()) {
|
||||||
attacking.get(i).addAssignedDamage(damageDealt, b);
|
attacker.addAssignedDamage(damageDealt, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block.size() == 0){
|
if (block.size() == 0){
|
||||||
// this damage is assigned to a player by setPlayerDamage()
|
// this damage is assigned to a player by setPlayerDamage()
|
||||||
addUnblockedAttacker(attacking.get(i));
|
addUnblockedAttacker(attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (attacking.get(i).hasFirstStrike() || attacking.get(i).hasDoubleStrike()) {
|
else if (attacker.hasFirstStrike() || attacker.hasDoubleStrike()) {
|
||||||
|
|
||||||
if (getAttackingPlayer().isHuman()) {// human attacks
|
if (getAttackingPlayer().isHuman()) {// human attacks
|
||||||
AllZone.Display.assignDamage(attacking.get(i), block, damageDealt);
|
AllZone.Display.assignDamage(attacker, block, damageDealt);
|
||||||
}
|
}
|
||||||
else {// computer attacks
|
else {// computer attacks
|
||||||
if (block.size() == 1) {
|
distributeAIDamage(attacker, block, damageDealt);
|
||||||
|
}
|
||||||
int trample = damageDealt - block.get(0).getKillDamage();
|
|
||||||
|
|
||||||
// trample
|
|
||||||
if (attacking.get(i).getKeyword().contains("Trample") && 0 < trample) {
|
|
||||||
block.get(0).addAssignedDamage(block.get(0).getKillDamage(), attacking.get(i));
|
|
||||||
this.addDefendingDamage(trample, attacking.get(i));
|
|
||||||
}
|
|
||||||
else block.get(0).addAssignedDamage(damageDealt, attacking.get(i));
|
|
||||||
}// 1 blocker
|
|
||||||
else {
|
|
||||||
distributeAIDamage(attacking.get(i), block, damageDealt);
|
|
||||||
}
|
|
||||||
} //Computer
|
|
||||||
|
|
||||||
}// if(hasFirstStrike || doubleStrike)
|
}// if(hasFirstStrike || doubleStrike)
|
||||||
}// for
|
}// for
|
||||||
}// setAssignedFirstStrikeDamage()
|
}// setAssignedFirstStrikeDamage()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
private void addAssignedFirstStrikeDamage(Card attacker, CardList block, int damage) {
|
private void distributeAIFirstStrikeDamage(Card attacker, CardList block, int damage) {
|
||||||
|
|
||||||
Card c = attacker;
|
Card c = attacker;
|
||||||
for (Card b : block) {
|
for (Card b : block) {
|
||||||
@@ -496,21 +492,8 @@ public class Combat {
|
|||||||
AllZone.Display.assignDamage(attacking.get(i), block, damageDealt);
|
AllZone.Display.assignDamage(attacking.get(i), block, damageDealt);
|
||||||
}
|
}
|
||||||
else {// computer attacks
|
else {// computer attacks
|
||||||
if (block.size() == 1) {
|
|
||||||
|
|
||||||
int trample = damageDealt - block.get(0).getKillDamage();
|
|
||||||
|
|
||||||
// trample
|
|
||||||
if (attacking.get(i).getKeyword().contains("Trample") && 0 < trample) {
|
|
||||||
block.get(0).addAssignedDamage(block.get(0).getKillDamage(), attacking.get(i));
|
|
||||||
this.addDefendingDamage(trample, attacking.get(i));
|
|
||||||
}
|
|
||||||
else block.get(0).addAssignedDamage(damageDealt, attacking.get(i));
|
|
||||||
}// 1 blocker
|
|
||||||
else {
|
|
||||||
distributeAIDamage(attacking.get(i), block, damageDealt);
|
distributeAIDamage(attacking.get(i), block, damageDealt);
|
||||||
}
|
}
|
||||||
} //Computer
|
|
||||||
}// if !hasFirstStrike ...
|
}// if !hasFirstStrike ...
|
||||||
}// for
|
}// for
|
||||||
|
|
||||||
@@ -520,25 +503,55 @@ public class Combat {
|
|||||||
|
|
||||||
private void distributeAIDamage(Card attacker, CardList block, int damage) {
|
private void distributeAIDamage(Card attacker, CardList block, int damage) {
|
||||||
Card c = attacker;
|
Card c = attacker;
|
||||||
for (Card b : block) {
|
|
||||||
if (b.getKillDamage() <= damage) {
|
|
||||||
damage -= b.getKillDamage();
|
|
||||||
CardList cl = new CardList();
|
|
||||||
cl.add(attacker);
|
|
||||||
|
|
||||||
b.addAssignedDamage(b.getKillDamage(), c);
|
if (block.size() == 1) {
|
||||||
// c.setAssignedDamage(c.getKillDamage());
|
|
||||||
|
Card blocker = block.get(0);
|
||||||
|
|
||||||
|
// trample
|
||||||
|
if (attacker.getKeyword().contains("Trample")) {
|
||||||
|
|
||||||
|
int damageNeeded = 0;
|
||||||
|
|
||||||
|
//TODO: if the human can be killed distribute only the minimum of damage on the blocker
|
||||||
|
|
||||||
|
damageNeeded = blocker.getEnoughDamageToKill(damage, attacker, true);
|
||||||
|
|
||||||
|
if (damageNeeded > damage)
|
||||||
|
damageNeeded = blocker.getLethalDamage();
|
||||||
|
else
|
||||||
|
damageNeeded = Math.min(blocker.getLethalDamage(),damageNeeded);
|
||||||
|
|
||||||
|
int trample = damage - damageNeeded;
|
||||||
|
|
||||||
|
if (0 < trample) {
|
||||||
|
blocker.addAssignedDamage(damageNeeded, attacker);
|
||||||
|
this.addDefendingDamage(trample, attacker);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}// for
|
else blocker.addAssignedDamage(damage, attacker);
|
||||||
|
}// 1 blocker
|
||||||
|
else {
|
||||||
|
for (Card b : block) {
|
||||||
|
if (b.getKillDamage() <= damage) {
|
||||||
|
damage -= b.getKillDamage();
|
||||||
|
CardList cl = new CardList();
|
||||||
|
cl.add(attacker);
|
||||||
|
|
||||||
// if attacker has no trample, and there's damage left, assign the rest
|
b.addAssignedDamage(b.getKillDamage(), c);
|
||||||
// to a random blocker
|
// c.setAssignedDamage(c.getKillDamage());
|
||||||
if (damage > 0 && !c.getKeyword().contains("Trample")) {
|
}
|
||||||
int index = CardUtil.getRandomIndex(block);
|
}// for
|
||||||
block.get(index).addAssignedDamage(damage, c);
|
|
||||||
damage = 0;
|
// if attacker has no trample, and there's damage left, assign the rest
|
||||||
} else if (c.getKeyword().contains("Trample")) {
|
// to a random blocker
|
||||||
this.addDefendingDamage(damage, c);
|
if (damage > 0 && !c.getKeyword().contains("Trample")) {
|
||||||
|
int index = CardUtil.getRandomIndex(block);
|
||||||
|
block.get(index).addAssignedDamage(damage, c);
|
||||||
|
damage = 0;
|
||||||
|
} else if (c.getKeyword().contains("Trample")) {
|
||||||
|
this.addDefendingDamage(damage, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}// setAssignedDamage()
|
}// setAssignedDamage()
|
||||||
|
|
||||||
@@ -548,8 +561,7 @@ public class Combat {
|
|||||||
|
|
||||||
boolean bFirstStrike = AllZone.Phase.is(Constant.Phase.Combat_FirstStrikeDamage);
|
boolean bFirstStrike = AllZone.Phase.is(Constant.Phase.Combat_FirstStrikeDamage);
|
||||||
|
|
||||||
HashMap<Card, Integer> defMap = bFirstStrike ? AllZone.Combat.getDefendingFirstStrikeDamageMap() :
|
HashMap<Card, Integer> defMap = AllZone.Combat.getDefendingDamageMap();
|
||||||
AllZone.Combat.getDefendingDamageMap();
|
|
||||||
|
|
||||||
for(Entry<Card, Integer> entry : defMap.entrySet()) {
|
for(Entry<Card, Integer> entry : defMap.entrySet()) {
|
||||||
player.addCombatDamage(entry.getValue(), entry.getKey());
|
player.addCombatDamage(entry.getValue(), entry.getKey());
|
||||||
|
|||||||
@@ -1359,12 +1359,7 @@ class Gui_MultipleBlockers3 extends JFrame {
|
|||||||
|
|
||||||
if (c.getName().equals("Player") && att.getKeyword().contains("Trample") && assignedLethalDamageToAllBlockers)
|
if (c.getName().equals("Player") && att.getKeyword().contains("Trample") && assignedLethalDamageToAllBlockers)
|
||||||
{
|
{
|
||||||
//what happens with Double Strike???
|
AllZone.Combat.addDefendingDamage(1, att);
|
||||||
if (att.getKeyword().contains("First Strike"))
|
|
||||||
AllZone.Combat.addDefendingFirstStrikeDamage(1, att);
|
|
||||||
else
|
|
||||||
AllZone.Combat.addDefendingDamage(1, att);
|
|
||||||
|
|
||||||
c.addAssignedDamage(1, att);
|
c.addAssignedDamage(1, att);
|
||||||
}
|
}
|
||||||
else if (!c.getName().equals("Player")){
|
else if (!c.getName().equals("Player")){
|
||||||
|
|||||||
@@ -1333,19 +1333,14 @@ class Gui_MultipleBlockers4 extends JFrame {
|
|||||||
boolean assignedLethalDamageToAllBlockers = true;
|
boolean assignedLethalDamageToAllBlockers = true;
|
||||||
for (Card crd : blockers )
|
for (Card crd : blockers )
|
||||||
{
|
{
|
||||||
if (crd.getTotalAssignedDamage() < ( crd.getNetDefense() - crd.getDamage() ))
|
if (crd.getLethalDamage() > 0 && (!att.getKeyword().contains("Deathtouch") || crd.getTotalAssignedDamage() < 1 ))
|
||||||
assignedLethalDamageToAllBlockers = false;
|
assignedLethalDamageToAllBlockers = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (c.getName().equals("Player") && att.getKeyword().contains("Trample") && assignedLethalDamageToAllBlockers)
|
if (c.getName().equals("Player") && att.getKeyword().contains("Trample") && assignedLethalDamageToAllBlockers)
|
||||||
{
|
{
|
||||||
//what happens with Double Strike???
|
AllZone.Combat.addDefendingDamage(1, att);
|
||||||
if (att.getKeyword().contains("First Strike"))
|
|
||||||
AllZone.Combat.addDefendingFirstStrikeDamage(1, att);
|
|
||||||
else
|
|
||||||
AllZone.Combat.addDefendingDamage(1, att);
|
|
||||||
|
|
||||||
c.addAssignedDamage(1, att);
|
c.addAssignedDamage(1, att);
|
||||||
}
|
}
|
||||||
else if (!c.getName().equals("Player")){
|
else if (!c.getName().equals("Player")){
|
||||||
|
|||||||
Reference in New Issue
Block a user