Merge branch 'Card-Forge:master' into master
@@ -48,10 +48,7 @@ import forge.util.collect.FCollection;
|
||||
import forge.util.collect.FCollectionView;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
@@ -360,35 +357,41 @@ public class AiAttackController {
|
||||
}
|
||||
|
||||
// this checks to make sure that the computer player doesn't lose when the human player attacks
|
||||
public final List<Card> notNeededAsBlockers(final List<Card> attackers) {
|
||||
public final List<Card> notNeededAsBlockers(final List<Card> currentAttackers, final List<Card> potentialAttackers) {
|
||||
//check for time walks
|
||||
if (ai.getGame().getPhaseHandler().getNextTurn().equals(ai)) {
|
||||
return attackers;
|
||||
return potentialAttackers;
|
||||
}
|
||||
// no need to block (already holding mana to cast fog next turn)
|
||||
if (!AiCardMemory.isMemorySetEmpty(ai, AiCardMemory.MemorySet.CHOSEN_FOG_EFFECT)) {
|
||||
// Don't send the card that'll do the fog effect to attack, it's unsafe!
|
||||
|
||||
List<Card> toRemove = Lists.newArrayList();
|
||||
for (Card c : attackers) {
|
||||
for (Card c : potentialAttackers) {
|
||||
if (AiCardMemory.isRememberedCard(ai, c, AiCardMemory.MemorySet.CHOSEN_FOG_EFFECT)) {
|
||||
toRemove.add(c);
|
||||
}
|
||||
}
|
||||
attackers.removeAll(toRemove);
|
||||
return attackers;
|
||||
potentialAttackers.removeAll(toRemove);
|
||||
return potentialAttackers;
|
||||
}
|
||||
|
||||
if (ai.isCardInPlay("Masako the Humorless")) {
|
||||
// "Tapped creatures you control can block as though they were untapped."
|
||||
return potentialAttackers;
|
||||
}
|
||||
|
||||
final CardCollection notNeededAsBlockers = new CardCollection(potentialAttackers);
|
||||
|
||||
final List<Card> vigilantes = new ArrayList<>();
|
||||
for (final Card c : myList) {
|
||||
if (c.getName().equals("Masako the Humorless")) {
|
||||
// "Tapped creatures you control can block as though they were untapped."
|
||||
return attackers;
|
||||
}
|
||||
for (final Card c : Iterables.concat(currentAttackers, potentialAttackers)) {
|
||||
// no need to block if an effect is in play which untaps all creatures
|
||||
// (pseudo-Vigilance akin to Awakening or Prophet of Kruphix)
|
||||
if (c.hasKeyword(Keyword.VIGILANCE) || ComputerUtilCard.willUntap(ai, c)) {
|
||||
vigilantes.add(c);
|
||||
} else if (currentAttackers.contains(c)) {
|
||||
// already attacking so can't block
|
||||
notNeededAsBlockers.add(c);
|
||||
}
|
||||
}
|
||||
// reduce the search space
|
||||
@@ -402,10 +405,8 @@ public class AiAttackController {
|
||||
}
|
||||
});
|
||||
|
||||
final CardCollection notNeededAsBlockers = new CardCollection(attackers);
|
||||
|
||||
// don't hold back creatures that can't block any of the human creatures
|
||||
final List<Card> blockers = getPossibleBlockers(attackers, opponentsAttackers, true);
|
||||
final List<Card> blockers = getPossibleBlockers(potentialAttackers, opponentsAttackers, true);
|
||||
|
||||
if (!blockers.isEmpty()) {
|
||||
notNeededAsBlockers.removeAll(blockers);
|
||||
@@ -476,12 +477,15 @@ public class AiAttackController {
|
||||
// these creatures will be available to block anyway
|
||||
notNeededAsBlockers.addAll(vigilantes);
|
||||
|
||||
// remove those that were only included to ensure a full picture for the baseline
|
||||
notNeededAsBlockers.removeAll(currentAttackers);
|
||||
|
||||
// Increase the total number of blockers needed by 1 if Finest Hour in play
|
||||
// (human will get an extra first attack with a creature that untaps)
|
||||
// In addition, if the computer guesses it needs no blockers, make sure
|
||||
// that it won't be surprised by Exalted
|
||||
final int humanExaltedBonus = defendingOpponent.countExaltedBonus();
|
||||
int blockersNeeded = attackers.size() - notNeededAsBlockers.size();
|
||||
int blockersNeeded = potentialAttackers.size() - notNeededAsBlockers.size();
|
||||
|
||||
if (humanExaltedBonus > 0) {
|
||||
final boolean finestHour = defendingOpponent.isCardInPlay("Finest Hour");
|
||||
@@ -511,6 +515,88 @@ public class AiAttackController {
|
||||
return notNeededAsBlockers;
|
||||
}
|
||||
|
||||
public void reinforceWithBanding(final Combat combat) {
|
||||
reinforceWithBanding(combat, null);
|
||||
}
|
||||
public void reinforceWithBanding(final Combat combat, final Card test) {
|
||||
CardCollection attackers = combat.getAttackers();
|
||||
if (attackers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> bandsWithString = Arrays.asList("Bands with Other Legendary Creatures",
|
||||
"Bands with Other Creatures named Wolves of the Hunt",
|
||||
"Bands with Other Dinosaurs");
|
||||
|
||||
List<Card> bandingCreatures = null;
|
||||
if (test == null) {
|
||||
bandingCreatures = CardLists.filter(myList, card -> card.hasKeyword(Keyword.BANDING) || card.hasAnyKeyword(bandsWithString));
|
||||
|
||||
// filter out anything that can't legally attack or is already declared as an attacker
|
||||
bandingCreatures = CardLists.filter(bandingCreatures, card -> !combat.isAttacking(card) && CombatUtil.canAttack(card));
|
||||
|
||||
bandingCreatures = notNeededAsBlockers(attackers, bandingCreatures);
|
||||
} else {
|
||||
// Test a specific creature for Banding
|
||||
if (test.hasKeyword(Keyword.BANDING) || test.hasAnyKeyword(bandsWithString)) {
|
||||
bandingCreatures = new CardCollection(test);
|
||||
}
|
||||
}
|
||||
|
||||
// respect global attack constraints
|
||||
GlobalAttackRestrictions restrict = GlobalAttackRestrictions.getGlobalRestrictions(ai, combat.getDefenders());
|
||||
int attackMax = restrict.getMax();
|
||||
if (attackMax >= attackers.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bandingCreatures != null) {
|
||||
List<String> evasionKeywords = Arrays.asList("Flying", "Horsemanship", "Shadow", "Plainswalk", "Islandwalk",
|
||||
"Forestwalk", "Mountainwalk", "Swampwalk");
|
||||
|
||||
// TODO: Assign to band with the best attacker for now, but needs better logic.
|
||||
for (Card c : bandingCreatures) {
|
||||
Card bestBand;
|
||||
|
||||
if (c.getNetPower() <= 0) {
|
||||
// Don't band a zero power creature if there's already a banding creature in a band
|
||||
attackers = CardLists.filter(attackers, card -> combat.getBandOfAttacker(card).getAttackers().size() == 1);
|
||||
}
|
||||
|
||||
Card bestAttacker = ComputerUtilCard.getBestCreatureAI(attackers);
|
||||
if (c.hasKeyword("Bands with Other Legendary Creatures")) {
|
||||
bestBand = ComputerUtilCard.getBestCreatureAI(CardLists.getType(attackers, "Legendary"));
|
||||
} else if (c.hasKeyword("Bands with Other Dinosaurs")) {
|
||||
bestBand = ComputerUtilCard.getBestCreatureAI(CardLists.getType(attackers, "Dinosaur"));
|
||||
} else if (c.hasKeyword("Bands with Other Creatures named Wolves of the Hunt")) {
|
||||
bestBand = ComputerUtilCard.getBestCreatureAI(CardLists.filter(attackers, CardPredicates.nameEquals("Wolves of the Hunt")));
|
||||
} else if (!c.hasAnyKeyword(evasionKeywords) && bestAttacker != null && bestAttacker.hasAnyKeyword(evasionKeywords)) {
|
||||
bestBand = ComputerUtilCard.getBestCreatureAI(CardLists.filter(attackers, card -> !card.hasAnyKeyword(evasionKeywords)));
|
||||
} else {
|
||||
bestBand = bestAttacker;
|
||||
}
|
||||
|
||||
if (c.getNetPower() <= 0) {
|
||||
attackers = combat.getAttackers(); // restore the unfiltered attackers
|
||||
}
|
||||
|
||||
if (bestBand != null) {
|
||||
GameEntity defender = combat.getDefenderByAttacker(bestBand);
|
||||
if (attackMax == -1) {
|
||||
// check with the local limitations vs. the chosen defender
|
||||
attackMax = restrict.getDefenderMax().get(defender) == null ? -1 : restrict.getDefenderMax().get(defender);
|
||||
}
|
||||
|
||||
if (attackMax == -1 || attackMax > combat.getAttackers().size()) {
|
||||
if (CombatUtil.canAttack(c, defender)) {
|
||||
combat.addAttacker(c, defender, combat.getBandOfAttacker(bestBand));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doAssault() {
|
||||
if (ai.isCardInPlay("Beastmaster Ascension") && this.attackers.size() > 1) {
|
||||
final CardCollectionView beastions = ai.getCardsIn(ZoneType.Battlefield, "Beastmaster Ascension");
|
||||
@@ -1199,7 +1285,7 @@ public class AiAttackController {
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println("Normal attack");
|
||||
|
||||
attackersLeft = notNeededAsBlockers(attackersLeft);
|
||||
attackersLeft = notNeededAsBlockers(combat.getAttackers(), attackersLeft);
|
||||
attackersLeft = sortAttackers(attackersLeft);
|
||||
|
||||
if ( LOG_AI_ATTACKS )
|
||||
|
||||
@@ -17,11 +17,7 @@
|
||||
*/
|
||||
package forge.ai;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
@@ -36,6 +32,7 @@ import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.combat.AttackingBand;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.combat.CombatUtil;
|
||||
import forge.game.cost.Cost;
|
||||
@@ -770,21 +767,52 @@ public class AiBlockController {
|
||||
tramplingAttackers = CardLists.filter(tramplingAttackers, Predicates.not(changesPTWhenBlocked(true)));
|
||||
|
||||
for (final Card attacker : tramplingAttackers) {
|
||||
boolean staticAssignCombatDamageAsUnblocked = StaticAbilityAssignCombatDamageAsUnblocked.assignCombatDamageAsUnblocked(attacker);
|
||||
|
||||
if (CombatUtil.getMinNumBlockersForAttacker(attacker, combat.getDefenderPlayerByAttacker(attacker)) > combat.getBlockers(attacker).size()
|
||||
|| StaticAbilityAssignCombatDamageAsUnblocked.assignCombatDamageAsUnblocked(attacker)
|
||||
|| attacker.hasKeyword("CARDNAME can't be blocked unless all creatures defending player controls block it.")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean needsMoreChumpBlockers = true;
|
||||
|
||||
// See if it's possible to tank up the damage with Banding
|
||||
List<String> bandsWithString = Arrays.asList("Bands with Other Legendary Creatures",
|
||||
"Bands with Other Creatures named Wolves of the Hunt",
|
||||
"Bands with Other Dinosaurs");
|
||||
if (AttackingBand.isValidBand(combat.getBlockers(attacker), true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
chumpBlockers = getPossibleBlockers(combat, attacker, blockersLeft, false);
|
||||
chumpBlockers.removeAll(combat.getBlockers(attacker));
|
||||
|
||||
// See if there's a Banding blocker that can tank the damage
|
||||
for (final Card blocker : chumpBlockers) {
|
||||
// Add an additional blocker if the current blockers are not
|
||||
// enough and the new one would suck some of the damage
|
||||
if (ComputerUtilCombat.getAttack(attacker) > ComputerUtilCombat.totalShieldDamage(attacker, combat.getBlockers(attacker))
|
||||
&& ComputerUtilCombat.shieldDamage(attacker, blocker) > 0
|
||||
&& CombatUtil.canBlock(attacker, blocker, combat) && ComputerUtilCombat.lifeInDanger(ai, combat)) {
|
||||
combat.addBlocker(attacker, blocker);
|
||||
if (blocker.hasKeyword(Keyword.BANDING) || blocker.hasAnyKeyword(bandsWithString)) {
|
||||
if (ComputerUtilCombat.getAttack(attacker) > ComputerUtilCombat.totalShieldDamage(attacker, combat.getBlockers(attacker))
|
||||
&& ComputerUtilCombat.shieldDamage(attacker, blocker) > 0
|
||||
&& CombatUtil.canBlock(attacker, blocker, combat) && ComputerUtilCombat.lifeInDanger(ai, combat)) {
|
||||
combat.addBlocker(attacker, blocker);
|
||||
needsMoreChumpBlockers = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (staticAssignCombatDamageAsUnblocked) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (needsMoreChumpBlockers) {
|
||||
for (final Card blocker : chumpBlockers) {
|
||||
// Add an additional blocker if the current blockers are not
|
||||
// enough and the new one would suck some of the damage
|
||||
if (ComputerUtilCombat.getAttack(attacker) > ComputerUtilCombat.totalShieldDamage(attacker, combat.getBlockers(attacker))
|
||||
&& ComputerUtilCombat.shieldDamage(attacker, blocker) > 0
|
||||
&& CombatUtil.canBlock(attacker, blocker, combat) && ComputerUtilCombat.lifeInDanger(ai, combat)) {
|
||||
combat.addBlocker(attacker, blocker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1304,6 +1304,9 @@ public class AiController {
|
||||
AiAttackController aiAtk = new AiAttackController(attacker);
|
||||
lastAttackAggression = aiAtk.declareAttackers(combat);
|
||||
|
||||
// Check if we can reinforce with Banding creatures
|
||||
aiAtk.reinforceWithBanding(combat);
|
||||
|
||||
// if invalid: just try an attack declaration that we know to be legal
|
||||
if (!CombatUtil.validateAttackers(combat)) {
|
||||
combat.clearAttackers();
|
||||
@@ -1618,8 +1621,7 @@ public class AiController {
|
||||
AiPlayDecision opinion = canPlayAndPayFor(sa);
|
||||
|
||||
// reset LastStateBattlefield
|
||||
sa.setLastStateBattlefield(CardCollection.EMPTY);
|
||||
sa.setLastStateGraveyard(CardCollection.EMPTY);
|
||||
sa.clearLastState();
|
||||
// PhaseHandler ph = game.getPhaseHandler();
|
||||
// System.out.printf("Ai thinks '%s' of %s -> %s @ %s %s >>> \n", opinion, sa.getHostCard(), sa, Lang.getPossesive(ph.getPlayerTurn().getName()), ph.getPhase());
|
||||
|
||||
|
||||
@@ -1406,6 +1406,39 @@ public class ComputerUtilCard {
|
||||
}
|
||||
}
|
||||
|
||||
if (keywords.contains("Banding") && !c.hasKeyword(Keyword.BANDING)) {
|
||||
if (phase.is(PhaseType.COMBAT_BEGIN) && phase.isPlayerTurn(ai) && !ComputerUtilCard.doesCreatureAttackAI(ai, c)) {
|
||||
// will this card participate in an attacking band?
|
||||
Card bandingCard = getPumpedCreature(ai, sa, c, toughness, power, keywords);
|
||||
// TODO: It may be possible to use AiController.getPredictedCombat here, but that makes it difficult to
|
||||
// use reinforceWithBanding through the attack controller, especially with the extra card parameter in mind
|
||||
AiAttackController aiAtk = new AiAttackController(ai);
|
||||
Combat predicted = new Combat(ai);
|
||||
aiAtk.declareAttackers(predicted);
|
||||
aiAtk.reinforceWithBanding(predicted, bandingCard);
|
||||
if (predicted.isAttacking(bandingCard) && predicted.getBandOfAttacker(bandingCard).getAttackers().size() > 1) {
|
||||
return true;
|
||||
}
|
||||
} else if (phase.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && combat != null) {
|
||||
// does this card block a Trample card or participate in a multi block?
|
||||
for (Card atk : combat.getAttackers()) {
|
||||
if (atk.getController().isOpponentOf(ai)) {
|
||||
CardCollection blockers = combat.getBlockers(atk);
|
||||
boolean hasBanding = false;
|
||||
for (Card blocker : blockers) {
|
||||
if (blocker.hasKeyword(Keyword.BANDING)) {
|
||||
hasBanding = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasBanding && ((blockers.contains(c) && blockers.size() > 1) || atk.hasKeyword(Keyword.TRAMPLE))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Player opp = ai.getWeakestOpponent();
|
||||
Card pumped = getPumpedCreature(ai, sa, c, toughness, power, keywords);
|
||||
List<Card> oppCreatures = opp.getCreaturesInPlay();
|
||||
|
||||
@@ -17,26 +17,17 @@
|
||||
*/
|
||||
package forge.ai;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.*;
|
||||
import forge.game.combat.AttackingBand;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.combat.CombatUtil;
|
||||
import forge.game.cost.CostPayment;
|
||||
@@ -57,6 +48,9 @@ import forge.util.MyRandom;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.collect.FCollection;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -2023,6 +2017,8 @@ public class ComputerUtilCombat {
|
||||
* distributeAIDamage.
|
||||
* </p>
|
||||
*
|
||||
* @param self
|
||||
* a {@link forge.game.player.Player} object.
|
||||
* @param attacker
|
||||
* a {@link forge.game.card.Card} object.
|
||||
* @param block
|
||||
@@ -2031,16 +2027,20 @@ public class ComputerUtilCombat {
|
||||
* @param defender
|
||||
* @param overrideOrder overriding combatant order
|
||||
*/
|
||||
public static Map<Card, Integer> distributeAIDamage(final Card attacker, final CardCollectionView block, final CardCollectionView remaining, int dmgCanDeal, GameEntity defender, boolean overrideOrder) {
|
||||
// TODO: Distribute defensive Damage (AI controls how damage is dealt to own cards) for Banding and Defensive Formation
|
||||
public static Map<Card, Integer> distributeAIDamage(final Player self, final Card attacker, final CardCollectionView block, final CardCollectionView remaining, int dmgCanDeal, GameEntity defender, boolean overrideOrder) {
|
||||
Map<Card, Integer> damageMap = Maps.newHashMap();
|
||||
Combat combat = attacker.getGame().getCombat();
|
||||
|
||||
boolean isAttacking = defender != null;
|
||||
|
||||
// Check for Banding, Defensive Formation
|
||||
boolean isAttackingMe = isAttacking && combat.getDefenderPlayerByAttacker(attacker).equals(self);
|
||||
boolean isBlockingMyBand = attacker.getController().isOpponentOf(self) && AttackingBand.isValidBand(block, true);
|
||||
final boolean aiDistributesBandingDmg = isAttackingMe || isBlockingMyBand;
|
||||
|
||||
final boolean hasTrample = attacker.hasKeyword(Keyword.TRAMPLE);
|
||||
|
||||
if (combat != null && remaining != null && hasTrample && attacker.isAttacking()) {
|
||||
if (combat != null && remaining != null && hasTrample && attacker.isAttacking() && !aiDistributesBandingDmg) {
|
||||
// if attacker has trample and some of its blockers are also blocking others it's generally a good idea
|
||||
// to assign those without trample first so we can maximize the damage to the defender
|
||||
for (final Card c : remaining) {
|
||||
@@ -2061,7 +2061,7 @@ public class ComputerUtilCombat {
|
||||
final Card blocker = block.getFirst();
|
||||
int dmgToBlocker = dmgCanDeal;
|
||||
|
||||
if (hasTrample && isAttacking) { // otherwise no entity to deliver damage via trample
|
||||
if (hasTrample && isAttacking && !aiDistributesBandingDmg) { // otherwise no entity to deliver damage via trample
|
||||
dmgToBlocker = getEnoughDamageToKill(blocker, dmgCanDeal, attacker, true);
|
||||
|
||||
if (dmgCanDeal < dmgToBlocker) {
|
||||
@@ -2077,7 +2077,7 @@ public class ComputerUtilCombat {
|
||||
}
|
||||
damageMap.put(blocker, dmgToBlocker);
|
||||
} // 1 blocker
|
||||
else {
|
||||
else if (!aiDistributesBandingDmg) {
|
||||
// Does the attacker deal lethal damage to all blockers
|
||||
//Blocking Order now determined after declare blockers
|
||||
Card lastBlocker = null;
|
||||
@@ -2098,13 +2098,26 @@ public class ComputerUtilCombat {
|
||||
}
|
||||
} // for
|
||||
|
||||
if (dmgCanDeal > 0 ) { // if any damage left undistributed,
|
||||
if (dmgCanDeal > 0) { // if any damage left undistributed,
|
||||
if (hasTrample && isAttacking) // if you have trample, deal damage to defending entity
|
||||
damageMap.put(null, dmgCanDeal);
|
||||
else if (lastBlocker != null) { // otherwise flush it into last blocker
|
||||
damageMap.put(lastBlocker, dmgCanDeal + damageMap.get(lastBlocker));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// In the event of Banding or Defensive Formation, assign max damage to the blocker who
|
||||
// can tank all the damage or to the worst blocker to lose as little as possible
|
||||
for (final Card b : block) {
|
||||
final int dmgToKill = getEnoughDamageToKill(b, dmgCanDeal, attacker, true);
|
||||
if (dmgToKill > dmgCanDeal) {
|
||||
damageMap.put(b, dmgCanDeal);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (damageMap.isEmpty()) {
|
||||
damageMap.put(ComputerUtilCard.getWorstCreatureAI(block), dmgCanDeal);
|
||||
}
|
||||
}
|
||||
return damageMap;
|
||||
}
|
||||
|
||||
@@ -962,7 +962,12 @@ public class ComputerUtilMana {
|
||||
ManaCostShard toPay, SpellAbility saPayment) {
|
||||
AbilityManaPart m = saPayment.getManaPart();
|
||||
if (m.isComboMana()) {
|
||||
m.setExpressChoice(ColorSet.fromMask(toPay.getColorMask()));
|
||||
// usually we'll want to produce color that matches the shard
|
||||
ColorSet shared = ColorSet.fromMask(toPay.getColorMask()).getSharedColors(ColorSet.fromNames(m.getComboColors(saPayment).split(" ")));
|
||||
// but other effects might still lead to a more permissive payment
|
||||
if (!shared.isColorless()) {
|
||||
m.setExpressChoice(ColorSet.fromMask(shared.iterator().next()));
|
||||
}
|
||||
getComboManaChoice(ai, saPayment, sa, cost);
|
||||
}
|
||||
else if (saPayment.getApi() == ApiType.ManaReflected) {
|
||||
|
||||
@@ -106,7 +106,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
|
||||
@Override
|
||||
public Map<Card, Integer> assignCombatDamage(Card attacker, CardCollectionView blockers, CardCollectionView remaining, int damageDealt, GameEntity defender, boolean overrideOrder) {
|
||||
return ComputerUtilCombat.distributeAIDamage(attacker, blockers, remaining, damageDealt, defender, overrideOrder);
|
||||
return ComputerUtilCombat.distributeAIDamage(player, attacker, blockers, remaining, damageDealt, defender, overrideOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -651,6 +651,21 @@ public class SpecialCardAi {
|
||||
}
|
||||
}
|
||||
|
||||
// Grothama, All-Devouring
|
||||
public static class GrothamaAllDevouring {
|
||||
public static boolean consider(final Player ai, final SpellAbility sa) {
|
||||
final Card source = sa.getHostCard();
|
||||
final Card devourer = AbilityUtils.getDefinedCards(source, sa.getParam("ExtraDefined"), sa).getFirst(); // maybe just getOriginalHost()?
|
||||
if (ai.getTeamMates(true).contains(devourer.getController())) {
|
||||
return false; // TODO: Currently, the AI doesn't ever fight its own (or allied) Grothama for card draw. This can be improved.
|
||||
}
|
||||
final Card fighter = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa).getFirst();
|
||||
boolean goodTradeOrNoTrade = devourer.canBeDestroyed() && (devourer.getNetPower() < fighter.getNetToughness() || !fighter.canBeDestroyed()
|
||||
|| ComputerUtilCard.evaluateCreature(devourer) > ComputerUtilCard.evaluateCreature(fighter));
|
||||
return goodTradeOrNoTrade && fighter.getNetPower() >= devourer.getNetToughness();
|
||||
}
|
||||
}
|
||||
|
||||
// Guilty Conscience
|
||||
public static class GuiltyConscience {
|
||||
public static Card getBestAttachTarget(final Player ai, final SpellAbility sa, final List<Card> list) {
|
||||
|
||||
@@ -112,7 +112,7 @@ public class ControlGainAi extends SpellAbilityAi {
|
||||
|
||||
// Don't steal something if I can't Attack without, or prevent it from blocking at least
|
||||
if (lose.contains("EOT")
|
||||
&& ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
||||
&& game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
||||
&& !sa.isTrigger()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ public class CounterAi extends SpellAbilityAi {
|
||||
String logic = sa.getParam("AILogic");
|
||||
if ("Never".equals(logic)) {
|
||||
return false;
|
||||
} else if (logic.startsWith("MinCMC.")) {
|
||||
} else if (logic.startsWith("MinCMC.")) { // TODO fix Daze and fold into AITgts
|
||||
int minCMC = Integer.parseInt(logic.substring(7));
|
||||
if (tgtCMC < minCMC) {
|
||||
return false;
|
||||
|
||||
@@ -59,8 +59,8 @@ public class DebuffAi extends SpellAbilityAi {
|
||||
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
||||
|| !game.getStack().isEmpty()) {
|
||||
// Instant-speed pumps should not be cast outside of combat when the
|
||||
// stack is empty
|
||||
if (!SpellAbilityAi.isSorcerySpeed(sa, ai)) {
|
||||
// stack is empty, unless there are specific activation phase requirements
|
||||
if (!SpellAbilityAi.isSorcerySpeed(sa, ai) && !sa.hasParam("ActivationPhases")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,7 @@ package forge.ai.ability;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.ai.ComputerUtil;
|
||||
import forge.ai.ComputerUtilAbility;
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.ComputerUtilCombat;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.ai.*;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.Card;
|
||||
@@ -32,9 +28,13 @@ public class FightAi extends SpellAbilityAi {
|
||||
sa.resetTargets();
|
||||
final Card source = sa.getHostCard();
|
||||
|
||||
// everything is defined or targeted above, can't do anything there?
|
||||
// everything is defined or targeted above, can't do anything there unless a specific logic is set
|
||||
if (sa.hasParam("Defined") && !sa.usesTargeting()) {
|
||||
// TODO extend Logic for cards like Arena or Grothama
|
||||
// TODO extend Logic for cards like Arena
|
||||
if ("Grothama".equals(sa.getParam("AILogic"))) { // Grothama, All-Devouring
|
||||
return SpecialCardAi.GrothamaAllDevouring.consider(ai, sa);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ public class FightAi extends SpellAbilityAi {
|
||||
|
||||
@Override
|
||||
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
|
||||
if (canPlayAI(ai, sa)) {
|
||||
if (checkApiLogic(ai, sa)) {
|
||||
return true;
|
||||
}
|
||||
if (!mandatory) {
|
||||
|
||||
@@ -223,7 +223,7 @@ public class GameAction {
|
||||
|
||||
// Don't copy Tokens, copy only cards leaving the battlefield
|
||||
// and returning to hand (to recreate their spell ability information)
|
||||
if (suppress || toBattlefield) {
|
||||
if (toBattlefield || (suppress && zoneTo.getZoneType().isHidden())) {
|
||||
copied = c;
|
||||
|
||||
if (lastKnownInfo == null) {
|
||||
@@ -295,7 +295,6 @@ public class GameAction {
|
||||
}
|
||||
|
||||
copied.setUnearthed(c.isUnearthed());
|
||||
copied.setTapped(false);
|
||||
|
||||
// need to copy counters when card enters another zone than hand or library
|
||||
if (lastKnownInfo.hasKeyword("Counters remain on CARDNAME as it moves to any zone other than a player's hand or library.") &&
|
||||
@@ -386,7 +385,7 @@ public class GameAction {
|
||||
}
|
||||
}
|
||||
|
||||
if (!zoneTo.is(ZoneType.Stack) && !suppress) {
|
||||
if (!zoneTo.is(ZoneType.Stack)) {
|
||||
// reset timestamp in changezone effects so they have same timestamp if ETB simultaneously
|
||||
copied.setTimestamp(game.getNextTimestamp());
|
||||
}
|
||||
@@ -600,7 +599,7 @@ public class GameAction {
|
||||
}
|
||||
|
||||
// only now that the LKI preserved it
|
||||
if (!zoneTo.is(ZoneType.Exile) && !zoneTo.is(ZoneType.Stack)) {
|
||||
if (!zoneTo.is(ZoneType.Stack)) {
|
||||
c.cleanupExiledWith();
|
||||
}
|
||||
|
||||
@@ -636,7 +635,6 @@ public class GameAction {
|
||||
}
|
||||
game.getTriggerHandler().runTrigger(TriggerType.ChangesController, runParams2, false);
|
||||
}
|
||||
// AllZone.getStack().chooseOrderOfSimultaneousStackEntryAll();
|
||||
|
||||
if (suppress) {
|
||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||
@@ -923,10 +921,6 @@ public class GameAction {
|
||||
return result;
|
||||
}
|
||||
public final Card exile(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
|
||||
if (game.isCardExiled(c)) {
|
||||
return c;
|
||||
}
|
||||
|
||||
final Zone origin = c.getZone();
|
||||
final PlayerZone removed = c.getOwner().getZone(ZoneType.Exile);
|
||||
final Card copied = moveTo(removed, c, cause, params);
|
||||
|
||||
@@ -561,9 +561,6 @@ public class AbilityUtils {
|
||||
}
|
||||
} else if (calcX[0].equals("OriginalHost")) {
|
||||
val = xCount(ability.getOriginalHost(), calcX[1], ability);
|
||||
} else if (calcX[0].equals("LastStateBattlefield") && ability instanceof SpellAbility) {
|
||||
Card c = ((SpellAbility) ability).getLastStateBattlefield().get(card);
|
||||
val = c == null ? 0 : xCount(c, calcX[1], ability);
|
||||
} else if (calcX[0].startsWith("ExiledWith")) {
|
||||
val = handlePaid(card.getExiledCards(), calcX[1], card, ability);
|
||||
} else if (calcX[0].startsWith("Convoked")) {
|
||||
|
||||
@@ -393,11 +393,16 @@ public abstract class SpellAbilityEffect {
|
||||
}
|
||||
|
||||
public static void addForgetOnMovedTrigger(final Card card, final String zone) {
|
||||
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ " + zone + " | ExcludedDestinations$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
|
||||
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ " + zone + " | ExcludedDestinations$ Stack,Exile | Destination$ Any | TriggerZones$ Command | Static$ True";
|
||||
String trig2 = "Mode$ Exiled | ValidCard$ Card.IsRemembered | TriggerZones$ Command | Static$ True";
|
||||
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, card, true);
|
||||
parsedTrigger.setOverridingAbility(getForgetSpellAbility(card));
|
||||
final Trigger parsedTrigger2 = TriggerHandler.parseTrigger(trig2, card, true);
|
||||
SpellAbility forget = getForgetSpellAbility(card);
|
||||
parsedTrigger.setOverridingAbility(forget);
|
||||
parsedTrigger2.setOverridingAbility(forget);
|
||||
card.addTrigger(parsedTrigger);
|
||||
card.addTrigger(parsedTrigger2);
|
||||
}
|
||||
|
||||
protected static void addForgetOnCastTrigger(final Card card) {
|
||||
|
||||
@@ -122,9 +122,8 @@ public class SacrificeEffect extends SpellAbilityEffect {
|
||||
String [] msgArray = msg.split(" & ");
|
||||
List<CardCollection> validTargetsList = new ArrayList<>(validArray.length);
|
||||
for (String subValid : validArray) {
|
||||
CardCollectionView validTargets = AbilityUtils.filterListByType(battlefield, subValid, sa);
|
||||
validTargets = CardLists.filter(validTargets, CardPredicates.canBeSacrificedBy(sa, true));
|
||||
validTargetsList.add(new CardCollection(validTargets));
|
||||
CardCollection validTargets = CardLists.filter(AbilityUtils.filterListByType(battlefield, subValid, sa), CardPredicates.canBeSacrificedBy(sa, true));
|
||||
validTargetsList.add(validTargets);
|
||||
}
|
||||
CardCollection chosenCards = new CardCollection();
|
||||
for (int i = 0; i < validArray.length; ++i) {
|
||||
|
||||
@@ -523,7 +523,13 @@ public class CardFactoryUtil {
|
||||
public static List<String> sharedKeywords(final Iterable<String> kw, final String[] restrictions,
|
||||
final Iterable<ZoneType> zones, final Card host, CardTraitBase ctb) {
|
||||
final List<String> filteredkw = Lists.newArrayList();
|
||||
final Player p = host.getController();
|
||||
Player p = null;
|
||||
if (ctb instanceof SpellAbility) {
|
||||
p = ((SpellAbility)ctb).getActivatingPlayer();
|
||||
}
|
||||
if (p == null) {
|
||||
p = host.getController();
|
||||
}
|
||||
CardCollectionView cardlist = p.getGame().getCardsIn(zones);
|
||||
final Set<String> landkw = Sets.newHashSet();
|
||||
final Set<String> protectionkw = Sets.newHashSet();
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package forge.game.combat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.keyword.Keyword;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AttackingBand {
|
||||
private CardCollection attackers = new CardCollection();
|
||||
private Boolean blocked = null; // even if all blockers were killed before FS or CD, band remains blocked
|
||||
@@ -26,7 +25,7 @@ public class AttackingBand {
|
||||
public void addAttacker(Card card) { attackers.add(card); }
|
||||
public void removeAttacker(Card card) { attackers.remove(card); }
|
||||
|
||||
public static boolean isValidBand(List<Card> band, boolean shareDamage) {
|
||||
public static boolean isValidBand(CardCollectionView band, boolean shareDamage) {
|
||||
if (band.isEmpty()) {
|
||||
// An empty band is not a valid band
|
||||
return false;
|
||||
@@ -64,7 +63,7 @@ public class AttackingBand {
|
||||
|
||||
public boolean canJoinBand(Card card) {
|
||||
// Trying to join an existing band, attackers should be non-empty and card should exist
|
||||
List<Card> newBand = new ArrayList<>(attackers);
|
||||
CardCollection newBand = new CardCollection(attackers);
|
||||
if (card != null) {
|
||||
newBand.add(card);
|
||||
}
|
||||
|
||||
@@ -1126,7 +1126,7 @@ public class CombatUtil {
|
||||
if (!canBlock(blocker, nextTurn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (isUnblockableFromLandwalk(attacker, blocker.getController())
|
||||
&& !blocker.hasKeyword("CARDNAME can block creatures with landwalk abilities as though they didn't have those abilities.")) {
|
||||
return false;
|
||||
|
||||
@@ -327,7 +327,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||
activeScheme = getZone(ZoneType.SchemeDeck).get(0);
|
||||
// gameAction moveTo ?
|
||||
game.getAction().moveTo(ZoneType.Command, activeScheme, null, moveParams);
|
||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||
|
||||
@@ -800,7 +799,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
restDamage = 2;
|
||||
}
|
||||
} else if (c.getName().equals("Elderscale Wurm")) {
|
||||
if (c.getController().equals(this) && getLife() - restDamage < 7) {
|
||||
if (c.getController().equals(this) && getLife() >= 7 && getLife() - restDamage < 7) {
|
||||
restDamage = getLife() - 7;
|
||||
if (restDamage < 0) {
|
||||
restDamage = 0;
|
||||
@@ -3268,9 +3267,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
|
||||
final TriggerHandler triggerHandler = game.getTriggerHandler();
|
||||
triggerHandler.suppressMode(TriggerType.ChangesZone);
|
||||
game.getAction().moveTo(ZoneType.Command, initiativeEffect, null, null);
|
||||
triggerHandler.clearSuppression(TriggerType.ChangesZone);
|
||||
com.add(initiativeEffect);
|
||||
triggerHandler.clearActiveTriggers(initiativeEffect, null);
|
||||
triggerHandler.registerActiveTrigger(initiativeEffect, false);
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ public class ReplacementHandler {
|
||||
chosenRE.setHasRun(true);
|
||||
hasRun.add(chosenRE);
|
||||
chosenRE.setOtherChoices(possibleReplacers);
|
||||
ReplacementResult res = executeReplacement(runParams, chosenRE, decider, game);
|
||||
ReplacementResult res = executeReplacement(runParams, chosenRE, decider);
|
||||
if (res == ReplacementResult.NotReplaced) {
|
||||
if (!possibleReplacers.isEmpty()) {
|
||||
res = run(event, runParams);
|
||||
@@ -287,8 +287,7 @@ public class ReplacementHandler {
|
||||
* the replacement effect to run
|
||||
*/
|
||||
private ReplacementResult executeReplacement(final Map<AbilityKey, Object> runParams,
|
||||
final ReplacementEffect replacementEffect, final Player decider, final Game game) {
|
||||
|
||||
final ReplacementEffect replacementEffect, final Player decider) {
|
||||
SpellAbility effectSA = null;
|
||||
|
||||
Card host = replacementEffect.getHostCard();
|
||||
@@ -441,7 +440,7 @@ public class ReplacementHandler {
|
||||
int damage = (int) runParams.get(AbilityKey.DamageAmount);
|
||||
Map<String, String> mapParams = re.getMapParams();
|
||||
|
||||
ReplacementResult res = executeReplacement(runParams, re, decider, game);
|
||||
ReplacementResult res = executeReplacement(runParams, re, decider);
|
||||
GameEntity newTarget = (GameEntity) runParams.get(AbilityKey.Affected);
|
||||
int newDamage = (int) runParams.get(AbilityKey.DamageAmount);
|
||||
|
||||
|
||||
@@ -201,6 +201,11 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
this.lastStateGraveyard = new CardCollection(lastStateGraveyard);
|
||||
}
|
||||
|
||||
public void clearLastState() {
|
||||
lastStateBattlefield = null;
|
||||
lastStateGraveyard = null;
|
||||
}
|
||||
|
||||
protected SpellAbility(final Card iSourceCard, final Cost toPay) {
|
||||
this(iSourceCard, toPay, null);
|
||||
}
|
||||
@@ -828,10 +833,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
if (isActivatedAbility()) {
|
||||
setXManaCostPaid(null);
|
||||
}
|
||||
|
||||
// reset last state when finished resolving
|
||||
setLastStateBattlefield(CardCollection.EMPTY);
|
||||
setLastStateGraveyard(CardCollection.EMPTY);
|
||||
}
|
||||
|
||||
// key for autoyield - the card description (including number) (if there is a card) plus the effect description
|
||||
|
||||
@@ -243,7 +243,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables {
|
||||
if (params.containsKey("ConditionTargetsSingleTarget")) {
|
||||
this.setTargetsSingleTarget(true);
|
||||
}
|
||||
} // setConditions
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
||||
@@ -189,7 +189,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
||||
this.setClassLevelOperator(params.get("ClassLevel").substring(0, 2));
|
||||
this.setClassLevel(params.get("ClassLevel").substring(2));
|
||||
}
|
||||
} // end setRestrictions()
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
||||
@@ -528,9 +528,6 @@ public class TriggerHandler {
|
||||
sa = sa.copy(host, controller, false);
|
||||
}
|
||||
|
||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
||||
|
||||
sa.setTrigger(regtrig);
|
||||
sa.setSourceTrigger(regtrig.getId());
|
||||
regtrig.setTriggeringObjects(sa, runParams);
|
||||
@@ -565,7 +562,6 @@ public class TriggerHandler {
|
||||
//wrapperAbility.setDescription(wrapperAbility.getStackDescription());
|
||||
//wrapperAbility.setDescription(wrapperAbility.toUnsuppressedString());
|
||||
|
||||
wrapperAbility.setLastStateBattlefield(game.getLastStateBattlefield());
|
||||
if (regtrig.isStatic()) {
|
||||
wrapperAbility.getActivatingPlayer().getController().playTrigger(host, wrapperAbility, isMandatory);
|
||||
} else {
|
||||
|
||||
@@ -279,11 +279,12 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
|
||||
sa.setTriggeringObject(AbilityKey.LifeAmount, castSA.getAmountLifePaid());
|
||||
sa.setTriggeringObjectsFrom(
|
||||
runParams,
|
||||
AbilityKey.Player,
|
||||
AbilityKey.Activator,
|
||||
AbilityKey.CurrentStormCount,
|
||||
AbilityKey.CurrentCastSpells
|
||||
);
|
||||
AbilityKey.CardLKI,
|
||||
AbilityKey.Player,
|
||||
AbilityKey.Activator,
|
||||
AbilityKey.CurrentStormCount,
|
||||
AbilityKey.CurrentCastSpells
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -44,7 +44,6 @@ import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.event.EventValueChangeType;
|
||||
import forge.game.event.GameEventCardStatsChanged;
|
||||
@@ -321,6 +320,14 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
|
||||
// Copied spells aren't cast per se so triggers shouldn't run for them.
|
||||
Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(sp.getHostCard().getController());
|
||||
|
||||
if (sp.isSpell() && !sp.isCopied()) {
|
||||
final Card lki = CardUtil.getLKICopy(sp.getHostCard());
|
||||
runParams.put(AbilityKey.CardLKI, lki);
|
||||
thisTurnCast.add(lki);
|
||||
sp.getActivatingPlayer().addSpellCastThisTurn();
|
||||
}
|
||||
|
||||
runParams.put(AbilityKey.Cost, sp.getPayCosts());
|
||||
runParams.put(AbilityKey.Activator, sp.getActivatingPlayer());
|
||||
runParams.put(AbilityKey.CastSA, si.getSpellAbility(true));
|
||||
@@ -462,10 +469,6 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
|
||||
GameActionUtil.checkStaticAfterPaying(sp.getHostCard());
|
||||
|
||||
if (sp.isSpell() && !sp.isCopied()) {
|
||||
thisTurnCast.add(CardUtil.getLKICopy(sp.getHostCard()));
|
||||
sp.getActivatingPlayer().addSpellCastThisTurn();
|
||||
}
|
||||
if (sp.isActivatedAbility() && sp.isPwAbility()) {
|
||||
sp.getActivatingPlayer().setActivateLoyaltyAbilityThisTurn(true);
|
||||
}
|
||||
@@ -694,8 +697,6 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
frozenStack.remove(si);
|
||||
game.updateStackForView();
|
||||
SpellAbility sa = si.getSpellAbility(false);
|
||||
sa.setLastStateBattlefield(CardCollection.EMPTY);
|
||||
sa.setLastStateGraveyard(CardCollection.EMPTY);
|
||||
game.fireEvent(new GameEventSpellRemovedFromStack(sa));
|
||||
}
|
||||
|
||||
|
||||
@@ -490,12 +490,17 @@ public class GameHUD extends Stage {
|
||||
private void setAudio(MusicPlaylist playlist) {
|
||||
if (playlist.equals(currentAudioPlaylist))
|
||||
return;
|
||||
System.out.println("Playlist: "+playlist);
|
||||
unloadAudio();
|
||||
System.out.println("Playlist: "+playlist);
|
||||
audio = getMusic(playlist);
|
||||
}
|
||||
|
||||
private Pair<FileHandle, Music> getMusic(MusicPlaylist playlist) {
|
||||
FileHandle file = Gdx.files.absolute(playlist.getNewRandomFilename());
|
||||
String filename = playlist.getNewRandomFilename();
|
||||
if (filename == null)
|
||||
return null;
|
||||
FileHandle file = Gdx.files.absolute(filename);
|
||||
Music music = Forge.getAssets().getMusic(file);
|
||||
if (music != null) {
|
||||
currentAudioPlaylist = playlist;
|
||||
@@ -776,7 +781,7 @@ public class GameHUD extends Stage {
|
||||
changeBGM(MusicPlaylist.WHITE);
|
||||
break;
|
||||
case "waste":
|
||||
changeBGM(MusicPlaylist.MENUS);
|
||||
changeBGM(MusicPlaylist.COLORLESS);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"maxRoadDistance": 1000,
|
||||
"biomesNames": [
|
||||
"world/biomes/base.json",
|
||||
"world/biomes/waste.json",
|
||||
"world/biomes/colorless.json",
|
||||
"world/biomes/white.json",
|
||||
"world/biomes/blue.json",
|
||||
"world/biomes/black.json",
|
||||
|
||||
BIN
forge-gui/res/adventure/common/music/menus/menu1.mp3
Normal file
@@ -23,11 +23,8 @@
|
||||
"height": 0.7,
|
||||
"color": "110903",
|
||||
"spriteNames": [
|
||||
"SwampTree",
|
||||
"SwampTree2",
|
||||
"DarkGras",
|
||||
"Skull",
|
||||
"SwampRock",
|
||||
"DarkWood",
|
||||
"Reed",
|
||||
"Waterlily",
|
||||
@@ -120,22 +117,46 @@
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/swamp_forest.png",
|
||||
"maskPath": "world/masks/ring.png",
|
||||
"structureAtlasPath": "world/structures/black_structures.atlas",
|
||||
"sourcePath": "world/structures/models/black.png",
|
||||
"maskPath": "world/structures/masks/ring.png",
|
||||
"height": 0.5,
|
||||
"width": 0.5,
|
||||
"symmetry": 8,
|
||||
"periodicOutput": false,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "swamp_forest",
|
||||
"color": "007000",
|
||||
"name": "water",
|
||||
"color": "00ffff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "swamp_water",
|
||||
"color": "005050",
|
||||
"name": "tree",
|
||||
"color": "004000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree2",
|
||||
"color": "008000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree3",
|
||||
"color": "ff00ff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree4",
|
||||
"color": "00f000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock",
|
||||
"color": "808080",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock2",
|
||||
"color": "ff0000",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
@@ -144,27 +165,41 @@
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/swamp_ruins.png",
|
||||
"maskPath": "world/masks/circle.png",
|
||||
"structureAtlasPath": "world/structures/black_structures.atlas",
|
||||
"sourcePath": "world/structures/models/black.png",
|
||||
"maskPath": "world/structures/masks/circle.png",
|
||||
"height": 0.20000002,
|
||||
"width": 0.20000002,
|
||||
"symmetry": 1,
|
||||
"periodicOutput": false,
|
||||
"symmetry": 8,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "deep_swamp",
|
||||
"color": "002000",
|
||||
"name": "muck",
|
||||
"color": "00ffff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "structure",
|
||||
"color": "505050",
|
||||
"name": "dead_tree",
|
||||
"color": "004000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "swamp_forest2",
|
||||
"color": "007000",
|
||||
"name": "dead_tree2",
|
||||
"color": "008000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "dead_tree3",
|
||||
"color": "ff00ff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock",
|
||||
"color": "808080",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock2",
|
||||
"color": "ff0000",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
"height": 0.7,
|
||||
"color": "10a2e0",
|
||||
"spriteNames": [
|
||||
"IslandTree",
|
||||
"Coral",
|
||||
"Shell"
|
||||
],
|
||||
"enemies": [
|
||||
@@ -108,47 +106,93 @@
|
||||
],
|
||||
"structures": [
|
||||
{
|
||||
"N":2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/water.png",
|
||||
"maskPath": "world/masks/circle.png",
|
||||
"height": 0.20000002,
|
||||
"width": 0.20000002,
|
||||
"structureAtlasPath": "world/structures/blue_structures.atlas",
|
||||
"sourcePath": "world/structures/models/blue.png",
|
||||
"maskPath": "world/structures/masks/circle.png",
|
||||
"height": 0.1,
|
||||
"width": 0.1,
|
||||
"symmetry": 8,
|
||||
"periodicOutput": false,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "water",
|
||||
"color": "0070a0",
|
||||
"color": "00ffff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "island_forest",
|
||||
"color": "00a000",
|
||||
"name": "tree",
|
||||
"color": "00ff00",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree2",
|
||||
"color": "008000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "pineapple",
|
||||
"color": "ffff00",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock",
|
||||
"color": "ff8000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock2",
|
||||
"color": "804000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock3",
|
||||
"color": "402000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock4",
|
||||
"color": "201000",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/island_forest.png",
|
||||
"maskPath": "world/masks/ring.png",
|
||||
"structureAtlasPath": "world/structures/blue_structures.atlas",
|
||||
"sourcePath": "world/structures/models/beach.png",
|
||||
"maskPath": "world/structures/masks/ring.png",
|
||||
"height": 0.5,
|
||||
"width": 0.5,
|
||||
"symmetry": 8,
|
||||
"periodicOutput": false,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "water",
|
||||
"color": "0070a0",
|
||||
"color": "00ffff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "island_forest",
|
||||
"color": "00a000",
|
||||
"name": "tree",
|
||||
"color": "00ff00",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree2",
|
||||
"color": "008000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "dune",
|
||||
"color": "ff8000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "dune2",
|
||||
"color": "402000",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
"distWeight": 1,
|
||||
"name": "waste",
|
||||
"tilesetAtlas": "world/tilesets/terrain.atlas",
|
||||
"tilesetName": "Waste",
|
||||
"tilesetName": "Colorless",
|
||||
"terrain": [
|
||||
{
|
||||
"spriteName": "Waste_1",
|
||||
"spriteName": "Colorless_1",
|
||||
"max": 0.2,
|
||||
"resolution": 5
|
||||
},
|
||||
{
|
||||
"spriteName": "Waste_2",
|
||||
"spriteName": "Colorless_2",
|
||||
"min": 0.8,
|
||||
"max": 1,
|
||||
"resolution": 5
|
||||
@@ -23,9 +23,7 @@
|
||||
"height": 0.85,
|
||||
"color": "aeaeae",
|
||||
"spriteNames": [
|
||||
"WasteTree",
|
||||
"Stone",
|
||||
"WasteRock"
|
||||
"Stone"
|
||||
],
|
||||
"enemies": [
|
||||
"Adept Black Wizard",
|
||||
@@ -118,44 +116,94 @@
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/waste_structure.png",
|
||||
"maskPath": "world/masks/circle.png",
|
||||
"periodicInput": false,
|
||||
"height": 0.20000002,
|
||||
"width": 0.20000002,
|
||||
"symmetry": 4,
|
||||
"structureAtlasPath": "world/structures/colorless_structures.atlas",
|
||||
"sourcePath": "world/structures/models/colorless.png",
|
||||
"maskPath": "world/structures/masks/circle.png",
|
||||
"height": 0.25,
|
||||
"width": 0.25,
|
||||
"symmetry": 8,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "waste_structure",
|
||||
"color": "444444",
|
||||
"name": "crater",
|
||||
"color": "808080",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "waste_mountain",
|
||||
"color": "9a9a9a",
|
||||
"name": "tree",
|
||||
"color": "ff0000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree2",
|
||||
"color": "00ff00",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree3",
|
||||
"color": "0000ff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree4",
|
||||
"color": "00ffff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock",
|
||||
"color": "ff00ff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "mountain",
|
||||
"color": "000000",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/hole.png",
|
||||
"maskPath": "world/masks/ring.png",
|
||||
"structureAtlasPath": "world/structures/colorless_structures.atlas",
|
||||
"sourcePath": "world/structures/models/colorless.png",
|
||||
"maskPath": "world/structures/masks/ring.png",
|
||||
"height": 0.5,
|
||||
"width": 0.5,
|
||||
"periodicOutput": false,
|
||||
"symmetry": 8,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "hole",
|
||||
"color": "111111",
|
||||
"color": "808080",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "waste_mountain",
|
||||
"color": "9a9a9a",
|
||||
"name": "tree",
|
||||
"color": "ff0000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree2",
|
||||
"color": "00ff00",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree3",
|
||||
"color": "0000ff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree4",
|
||||
"color": "00ffff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock",
|
||||
"color": "ff00ff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "mountain",
|
||||
"color": "000000",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
@@ -23,9 +23,6 @@
|
||||
"height": 0.7,
|
||||
"color": "59a650",
|
||||
"spriteNames": [
|
||||
"WoodTree",
|
||||
"WoodTree2",
|
||||
"Bush",
|
||||
"Stump",
|
||||
"Moss",
|
||||
"Stone",
|
||||
@@ -122,39 +119,66 @@
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/forest.png",
|
||||
"maskPath": "world/masks/circle.png",
|
||||
"height": 0.20000002,
|
||||
"width": 0.20000002,
|
||||
"structureAtlasPath": "world/structures/green_structures.atlas",
|
||||
"sourcePath": "world/structures/models/green.png",
|
||||
"maskPath": "world/structures/masks/circle.png",
|
||||
"height": 0.5,
|
||||
"width": 0.5,
|
||||
"symmetry": 1,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "forest",
|
||||
"color": "007000",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/lake.png",
|
||||
"maskPath": "world/masks/ring.png",
|
||||
"height": 0.5,
|
||||
"width": 0.5,
|
||||
"periodicOutput": false,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "lake",
|
||||
"color": "0070a0",
|
||||
"name": "water",
|
||||
"color": "000080",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "forest2",
|
||||
"color": "009000",
|
||||
"name": "tree",
|
||||
"color": "008000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree2",
|
||||
"color": "004000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "vine",
|
||||
"color": "8080ff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree3",
|
||||
"color": "00c000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree4",
|
||||
"color": "00f000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree5",
|
||||
"color": "006000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock",
|
||||
"color": "808080",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "mountain",
|
||||
"color": "ff0000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "plant",
|
||||
"color": "800000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "bush",
|
||||
"color": "ff8080",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
"height": 1,
|
||||
"color": "110903",
|
||||
"spriteNames": [
|
||||
"Skull",
|
||||
"PlainsRock"
|
||||
"Skull"
|
||||
],
|
||||
"enemies": [
|
||||
"Ammit",
|
||||
@@ -60,9 +59,9 @@
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/mountain.png",
|
||||
"maskPath": "world/masks/circle.png",
|
||||
"structureAtlasPath": "world/structures/structures.atlas",
|
||||
"sourcePath": "world/structures/models/mountain.png",
|
||||
"maskPath": "world/structures/masks/circle.png",
|
||||
"height": 0.5,
|
||||
"width": 0.5,
|
||||
"symmetry": 8,
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"structureAtlasPath": "world/structures/structures.atlas",
|
||||
"sourcePath": "world/models/fill.png",
|
||||
"maskPath": "world/masks/fill.png",
|
||||
"height": 0.99,
|
||||
|
||||
@@ -45,9 +45,9 @@
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/mountain.png",
|
||||
"maskPath": "world/masks/circle.png",
|
||||
"structureAtlasPath": "world/structures/structures.atlas",
|
||||
"sourcePath": "world/structures/models/mountain.png",
|
||||
"maskPath": "world/structures/masks/circle.png",
|
||||
"height": 0.5,
|
||||
"width": 0.5,
|
||||
"periodicOutput": false,
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
"height": 0.7,
|
||||
"color": "b63729",
|
||||
"spriteNames": [
|
||||
"MountainTree",
|
||||
"MountainTree2",
|
||||
"MountainRock",
|
||||
"Gravel"
|
||||
],
|
||||
"enemies": [
|
||||
@@ -127,21 +124,41 @@
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/mountain.png",
|
||||
"maskPath": "world/masks/ring.png",
|
||||
"structureAtlasPath": "world/structures/red_structures.atlas",
|
||||
"sourcePath": "world/structures/models/red.png",
|
||||
"maskPath": "world/structures/masks/ring.png",
|
||||
"height": 0.5,
|
||||
"width": 0.5,
|
||||
"periodicOutput": false,
|
||||
"symmetry": 8,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "mountain",
|
||||
"color": "a07020",
|
||||
"color": "ff0000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "mountain_forest",
|
||||
"color": "007000",
|
||||
"name": "tree",
|
||||
"color": "00ff00",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree2",
|
||||
"color": "00ffff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree3",
|
||||
"color": "0000ff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree4",
|
||||
"color": "ff00ff",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock",
|
||||
"color": "ffff00",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
@@ -149,15 +166,37 @@
|
||||
{
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/lava.png",
|
||||
"maskPath": "world/masks/circle.png",
|
||||
"structureAtlasPath": "world/structures/red_structures.atlas",
|
||||
"sourcePath": "world/structures/models/volcano.png",
|
||||
"maskPath": "world/structures/masks/circle.png",
|
||||
"height": 0.2,
|
||||
"width": 0.2,
|
||||
"N": 2,
|
||||
"symmetry": 8,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "lava",
|
||||
"color": "ff5000",
|
||||
"color": "ffff00",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "mountain",
|
||||
"color": "ff0000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "dead_tree",
|
||||
"color": "000000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "dead_tree2",
|
||||
"color": "808080",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock",
|
||||
"color": "0000ff",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
"height": 0.5,
|
||||
"color": "efe697",
|
||||
"spriteNames": [
|
||||
"PlainsRock",
|
||||
"Skull"
|
||||
],
|
||||
"enemies": [
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
"height": 0.7,
|
||||
"color": "efe697",
|
||||
"spriteNames": [
|
||||
"PlainsTree",
|
||||
"Cactus",
|
||||
"PlainsRock",
|
||||
"DarkGras"
|
||||
],
|
||||
"enemies": [
|
||||
@@ -117,33 +114,74 @@
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/plains_forest.png",
|
||||
"maskPath": "world/masks/circle.png",
|
||||
"structureAtlasPath": "world/structures/white_structures.atlas",
|
||||
"sourcePath": "world/structures/models/white.png",
|
||||
"maskPath": "world/structures/masks/circle.png",
|
||||
"height": 0.20000002,
|
||||
"width": 0.20000002,
|
||||
"symmetry": 8,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "plains_forest",
|
||||
"color": "9c4000",
|
||||
"name": "tree",
|
||||
"color": "ff8000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree2",
|
||||
"color": "008000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "tree3",
|
||||
"color": "00ff00",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"N": 2,
|
||||
"x": 0.5,
|
||||
"y": 0.5,
|
||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
||||
"sourcePath": "world/models/plateau.png",
|
||||
"maskPath": "world/masks/ring.png",
|
||||
"symmetry": 8,
|
||||
"structureAtlasPath": "world/structures/white_structures.atlas",
|
||||
"sourcePath": "world/structures/models/desert.png",
|
||||
"maskPath": "world/structures/masks/ring.png",
|
||||
"height": 0.5,
|
||||
"width": 0.5,
|
||||
"periodicOutput": false,
|
||||
"mappingInfo": [
|
||||
{
|
||||
"name": "plateau",
|
||||
"color": "caaa66",
|
||||
"color": "804000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "rock",
|
||||
"color": "402000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "mesa",
|
||||
"color": "201000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "plateau",
|
||||
"color": "804000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "cactus",
|
||||
"color": "00ff00",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "cactus2",
|
||||
"color": "008000",
|
||||
"collision": true
|
||||
},
|
||||
{
|
||||
"name": "cactus3",
|
||||
"color": "004000",
|
||||
"collision": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -6369,9 +6369,7 @@
|
||||
"IdentityBlack",
|
||||
"IdentityGreen",
|
||||
"IdentityAbzan",
|
||||
"BiomeColorless",
|
||||
"BiomeWhite",
|
||||
"BiomeBlack"
|
||||
"BiomeBlue"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -7242,7 +7240,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"colors": "W",
|
||||
"colors": "GW",
|
||||
"questTags": [
|
||||
"Elephant",
|
||||
"Beast",
|
||||
@@ -12544,7 +12542,7 @@
|
||||
"spawnRate": 1,
|
||||
"difficulty": 0.1,
|
||||
"speed": 25,
|
||||
"scale": 0.6,
|
||||
"scale": 1.3,
|
||||
"life": 11,
|
||||
"rewards": [
|
||||
{
|
||||
|
||||
@@ -5,289 +5,382 @@ filter: Nearest,Nearest
|
||||
repeat: none
|
||||
DarkWood
|
||||
xy: 0, 0
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
DarkWood
|
||||
xy: 16, 0
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
DarkWood
|
||||
xy: 32, 0
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
DarkWood
|
||||
xy: 48, 0
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Reed
|
||||
xy: 64, 0
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Reed
|
||||
xy: 80, 0
|
||||
size: 16, 16
|
||||
Reed
|
||||
xy: 64, 16
|
||||
size: 16, 16
|
||||
Reed
|
||||
xy: 80, 16
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
DarkWood
|
||||
xy: 96, 0
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
DarkWood
|
||||
xy: 112, 0
|
||||
size: 16, 16
|
||||
Waterlily
|
||||
xy: 96, 16
|
||||
size: 16, 16
|
||||
Waterlily
|
||||
xy: 112, 16
|
||||
size: 16, 16
|
||||
Shroom
|
||||
xy: 96, 32
|
||||
size: 16, 16
|
||||
Shroom
|
||||
xy: 96, 48
|
||||
size: 16, 16
|
||||
Shroom2
|
||||
xy: 112, 32
|
||||
size: 16, 16
|
||||
Shroom2
|
||||
xy: 112, 48
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
DarkWood
|
||||
xy: 0, 16
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
DarkWood
|
||||
xy: 16, 16
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
DarkWood
|
||||
xy: 32, 16
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
DarkWood
|
||||
xy: 48, 16
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Reed
|
||||
xy: 64, 16
|
||||
size: 16, 16
|
||||
Reed
|
||||
xy: 80, 16
|
||||
size: 16, 16
|
||||
Waterlily
|
||||
xy: 96, 16
|
||||
size: 16, 16
|
||||
Waterlily
|
||||
xy: 112, 16
|
||||
size: 16, 16
|
||||
DarkGras
|
||||
xy: 0, 32
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
DarkGras
|
||||
xy: 16, 32
|
||||
size: 16, 16
|
||||
DarkGras
|
||||
xy: 0, 48
|
||||
size: 16, 16
|
||||
DarkGras
|
||||
xy: 16, 48
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 32, 32
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 48, 32
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 32, 48
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 48, 48
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Gravel
|
||||
xy: 64, 32
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Gravel
|
||||
xy: 80, 32
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Shroom
|
||||
xy: 96, 32
|
||||
size: 16, 16
|
||||
Shroom2
|
||||
xy: 112, 32
|
||||
size: 16, 16
|
||||
DarkGras
|
||||
xy: 0, 48
|
||||
size: 16, 16
|
||||
DarkGras
|
||||
xy: 16, 48
|
||||
size: 16, 16
|
||||
Shroom
|
||||
xy: 96, 48
|
||||
size: 16, 16
|
||||
Shroom2
|
||||
xy: 112, 48
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 32, 48
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 48, 48
|
||||
size: 16, 16
|
||||
Gravel
|
||||
xy: 64, 48
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Gravel
|
||||
xy: 80, 48
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Flower
|
||||
xy: 0, 64
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Flower
|
||||
xy: 16, 64
|
||||
size: 16, 16
|
||||
Flower
|
||||
xy: 0, 80
|
||||
size: 16, 16
|
||||
Flower
|
||||
xy: 16, 80
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 32, 64
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 48, 64
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 32, 80
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 48, 80
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Moss
|
||||
xy: 64, 64
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Moss
|
||||
xy: 80, 64
|
||||
size: 16, 16
|
||||
Moss
|
||||
xy: 64, 80
|
||||
size: 16, 16
|
||||
Moss
|
||||
xy: 80, 80
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Wood
|
||||
xy: 96, 64
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Wood
|
||||
xy: 112, 64
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Flower
|
||||
xy: 0, 80
|
||||
size: 16, 16
|
||||
Flower
|
||||
xy: 16, 80
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 32, 80
|
||||
size: 16, 16
|
||||
Stone
|
||||
xy: 48, 80
|
||||
size: 16, 16
|
||||
Moss
|
||||
xy: 64, 80
|
||||
size: 16, 16
|
||||
Moss
|
||||
xy: 80, 80
|
||||
size: 16, 16
|
||||
Wood
|
||||
xy: 96, 80
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Wood
|
||||
xy: 112, 80
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
WasteTree
|
||||
xy: 0, 96
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
WasteTree
|
||||
xy: 16, 96
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
WasteTree
|
||||
xy: 32, 96
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
WasteRock
|
||||
xy: 48, 96
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
WasteRock
|
||||
xy: 64, 96
|
||||
size: 16, 16
|
||||
SwampTree
|
||||
xy: 0, 112
|
||||
size: 16, 16
|
||||
SwampTree
|
||||
xy: 16, 112
|
||||
size: 16, 16
|
||||
SwampTree
|
||||
xy: 32, 112
|
||||
size: 16, 16
|
||||
Skull
|
||||
xy: 48, 112
|
||||
size: 16, 16
|
||||
Skull
|
||||
xy: 112, 144
|
||||
size: 16, 16
|
||||
Skull
|
||||
xy: 112, 128
|
||||
size: 16, 16
|
||||
SwampRock
|
||||
xy: 64, 112
|
||||
size: 16, 16
|
||||
SwampRock
|
||||
xy: 80, 112
|
||||
size: 16, 16
|
||||
SwampTree2
|
||||
xy: 96, 112
|
||||
size: 16, 16
|
||||
SwampTree2
|
||||
xy: 112, 112
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Placeholder
|
||||
xy: 80, 96
|
||||
size: 16,16
|
||||
SwampTree2
|
||||
xy: 96, 96
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
SwampTree2
|
||||
xy: 112, 96
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
SwampTree
|
||||
xy: 0, 112
|
||||
size: 16, 16
|
||||
SwampTree
|
||||
xy: 16, 112
|
||||
size: 16, 16
|
||||
SwampTree
|
||||
xy: 32, 112
|
||||
size: 16, 16
|
||||
Skull
|
||||
xy: 48, 112
|
||||
size: 16, 16
|
||||
SwampRock
|
||||
xy: 64, 112
|
||||
size: 16, 16
|
||||
SwampRock
|
||||
xy: 80, 112
|
||||
size: 16, 16
|
||||
SwampTree2
|
||||
xy: 96, 112
|
||||
size: 16, 16
|
||||
SwampTree2
|
||||
xy: 112, 112
|
||||
size: 16, 16
|
||||
PlainsTree
|
||||
xy: 0, 128
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
PlainsTree
|
||||
xy: 16, 128
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Cactus
|
||||
xy: 32, 128
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Cactus
|
||||
xy: 48, 128
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Cactus
|
||||
xy: 64, 128
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
PlainsRock
|
||||
xy: 70, 128
|
||||
size: 16, 16
|
||||
xy: 80, 128
|
||||
size: 16, 16
|
||||
PlainsRock
|
||||
xy: 96, 128
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Skull
|
||||
xy: 112, 128
|
||||
size: 16, 16
|
||||
IslandTree
|
||||
xy: 0, 144
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
IslandTree
|
||||
xy: 16, 144
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Coral
|
||||
xy: 32, 144
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Shell
|
||||
xy: 48, 144
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Shell
|
||||
xy: 64, 144
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Placeholder
|
||||
xy: 80, 144
|
||||
size: 16, 16
|
||||
Placeholder
|
||||
xy: 96, 144
|
||||
size: 16, 16
|
||||
Skull
|
||||
xy: 112, 144
|
||||
size: 16, 16
|
||||
WoodTree
|
||||
xy: 0, 160
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
WoodTree
|
||||
xy: 16, 160
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
WoodTree
|
||||
xy: 32, 160
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
WoodTree
|
||||
xy: 48, 160
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
WoodTree2
|
||||
xy: 64, 160
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
WoodTree2
|
||||
xy: 80, 160
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Bush
|
||||
xy: 96, 160
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
Stump
|
||||
xy: 112, 160
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
MountainTree
|
||||
xy: 0, 176
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
MountainTree
|
||||
xy: 16, 176
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
MountainTree2
|
||||
xy: 32, 176
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
MountainTree2
|
||||
xy: 48, 176
|
||||
size: 16, 16
|
||||
MountainTree2
|
||||
xy: 96, 176
|
||||
size: 16, 16
|
||||
MountainTree2
|
||||
xy: 112, 176
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
MountainRock
|
||||
xy: 64, 176
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
MountainRock
|
||||
xy: 80, 176
|
||||
size: 16, 16
|
||||
size: 16, 16
|
||||
MountainTree2
|
||||
xy: 96, 176
|
||||
size: 16, 16
|
||||
MountainTree2
|
||||
xy: 112, 176
|
||||
size: 16, 16
|
||||
WoodTree
|
||||
xy: 0, 192
|
||||
size: 16, 16
|
||||
AutumnTree
|
||||
xy: 16, 192
|
||||
size: 16, 16
|
||||
WinterTree
|
||||
xy: 32, 192
|
||||
size: 16, 16
|
||||
AutumnTree
|
||||
xy: 48, 192
|
||||
size: 16, 16
|
||||
Coral
|
||||
xy: 64, 192
|
||||
size: 16, 16
|
||||
SnowMountain
|
||||
xy: 80, 192
|
||||
size: 16, 16
|
||||
Coral
|
||||
xy: 96, 192
|
||||
size: 16, 16
|
||||
AutumnTree
|
||||
xy: 112, 192
|
||||
size: 16, 16
|
||||
Placeholder
|
||||
xy: 0, 208
|
||||
size: 16, 16
|
||||
AutumnTree
|
||||
xy: 16, 208
|
||||
size: 16, 16
|
||||
SwampTree
|
||||
xy: 32, 208
|
||||
size: 16, 16
|
||||
Coral
|
||||
xy: 48, 208
|
||||
size: 16, 16
|
||||
WoodTree
|
||||
xy: 64, 208
|
||||
size: 16, 16
|
||||
IslandRock
|
||||
xy: 80, 208
|
||||
size: 16, 16
|
||||
WoodRock
|
||||
xy: 96, 208
|
||||
size: 16, 16
|
||||
Placeholder
|
||||
xy: 112, 208
|
||||
size: 16, 16
|
||||
LargeWoodRock
|
||||
xy: 0, 224
|
||||
size: 32, 32
|
||||
LargeIslandRock
|
||||
xy: 32, 224
|
||||
size: 32, 32
|
||||
LargeWasteRock
|
||||
xy: 64, 224
|
||||
size: 32, 32
|
||||
LargeMountainRock
|
||||
xy: 96, 224
|
||||
size: 32, 32
|
||||
size: 32, 32
|
||||
LargePlainsRock
|
||||
xy: 96, 256
|
||||
size: 32, 32
|
||||
size: 32, 32
|
||||
Placeholder
|
||||
xy: 0, 256
|
||||
size: 16, 16
|
||||
WasteRock
|
||||
xy: 16, 256
|
||||
size: 16, 16
|
||||
LargeSwampRock
|
||||
xy: 32, 256
|
||||
size: 32, 32
|
||||
size: 32, 32
|
||||
PlainsRock
|
||||
xy: 64, 256
|
||||
size: 16, 16
|
||||
PlainsRock
|
||||
xy: 80, 256
|
||||
size: 16, 16
|
||||
LargePlainsRock
|
||||
xy: 96, 256
|
||||
size: 32, 32
|
||||
WoodRock
|
||||
xy: 0, 272
|
||||
size: 16, 16
|
||||
SwampRock
|
||||
xy: 16, 272
|
||||
size: 16, 16
|
||||
WinterTree:
|
||||
xy: 64, 272
|
||||
size: 16, 16
|
||||
WinterTree:
|
||||
xy: 80, 272
|
||||
size: 16, 16
|
||||
@@ -2,7 +2,7 @@
|
||||
"textureAtlas":"world/sprites/map_sprites.atlas",
|
||||
"sprites":[
|
||||
{
|
||||
"name":"DarkWood",
|
||||
"name":"DarkWood",
|
||||
"startArea":0.2,
|
||||
"endArea":0.7,
|
||||
"layer":-1,
|
||||
@@ -22,7 +22,7 @@
|
||||
"layer":-1,
|
||||
"density":0.03
|
||||
},{
|
||||
"name":"Reed",
|
||||
"name":"Reed",
|
||||
"startArea":0.9,
|
||||
"endArea":0.99,
|
||||
"layer":0,
|
||||
@@ -46,7 +46,7 @@
|
||||
"name":"Stone",
|
||||
"startArea":0.2,
|
||||
"endArea":0.7,
|
||||
"layer":-1,
|
||||
"layer":-1,
|
||||
"resolution" :5,
|
||||
"density":0.01
|
||||
},{
|
||||
@@ -79,21 +79,21 @@
|
||||
"name":"WasteTree",
|
||||
"startArea":0.0,
|
||||
"endArea":0.2,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :10,
|
||||
"density":0.7
|
||||
},{
|
||||
"name":"WasteRock",
|
||||
"startArea":0.8,
|
||||
"endArea":1.0,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :10,
|
||||
"density":0.5
|
||||
},{
|
||||
"name":"SwampTree",
|
||||
"startArea":0.8,
|
||||
"endArea":1.0,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :10,
|
||||
"density":0.5
|
||||
},{
|
||||
@@ -106,45 +106,45 @@
|
||||
"name":"SwampRock",
|
||||
"startArea":0.5,
|
||||
"endArea":0.6,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"density":0.1
|
||||
},{
|
||||
"name":"SwampTree2",
|
||||
"startArea":0.0,
|
||||
"endArea":0.2,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :10,
|
||||
"density":0.7
|
||||
},{
|
||||
"name":"PlainsTree",
|
||||
"startArea":0.0,
|
||||
"endArea":0.2,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :10,
|
||||
"density":0.7
|
||||
},{
|
||||
"name":"Cactus",
|
||||
"startArea":0.5,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"endArea":0.7,
|
||||
"density":0.06
|
||||
},{
|
||||
"name":"PlainsRock",
|
||||
"startArea":0.7,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"endArea":0.99,
|
||||
"density":0.06
|
||||
},{
|
||||
"name":"IslandTree",
|
||||
"startArea":0.0,
|
||||
"endArea":0.2,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :10,
|
||||
"density":0.7
|
||||
},{
|
||||
"name":"Coral",
|
||||
"startArea":0.0,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"endArea":0.9,
|
||||
"density":0.01
|
||||
},{
|
||||
@@ -157,65 +157,65 @@
|
||||
"name":"WoodTree",
|
||||
"startArea":0.0,
|
||||
"endArea":0.2,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :10,
|
||||
"density":0.7
|
||||
},{
|
||||
"name":"WoodTree2",
|
||||
"startArea":0.8,
|
||||
"endArea":0.99,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :5,
|
||||
"density":0.7
|
||||
},{
|
||||
"name":"Bush",
|
||||
"startArea":0.0,
|
||||
"endArea":0.2,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :5,
|
||||
"density":0.4
|
||||
},{
|
||||
"name":"Stump",
|
||||
"startArea":0.0,
|
||||
"layer":0,
|
||||
"layer":-1,
|
||||
"endArea":0.9,
|
||||
"density":0.01
|
||||
},{
|
||||
"name":"MountainTree",
|
||||
"startArea":0.0,
|
||||
"endArea":0.2,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :5,
|
||||
"density":0.7
|
||||
},{
|
||||
"name":"MountainTree2",
|
||||
"startArea":0.8,
|
||||
"endArea":0.99,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"resolution" :5,
|
||||
"density":0.7
|
||||
},{
|
||||
"name":"MountainRock",
|
||||
"startArea":0.1,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"endArea":0.9,
|
||||
"density":0.08
|
||||
},{
|
||||
"name":"LargeMountainRock",
|
||||
"startArea":0.0,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"endArea":0.9,
|
||||
"density":0.02
|
||||
},{
|
||||
"name":"LargePlainsRock",
|
||||
"startArea":0.0,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"endArea":0.9,
|
||||
"density":0.01
|
||||
},{
|
||||
"name":"LargeSwampRock",
|
||||
"startArea":0.0,
|
||||
"layer":0,
|
||||
"layer":1,
|
||||
"endArea":0.9,
|
||||
"density":0.01
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
black_structures.png
|
||||
size: 192,192
|
||||
format: RGBA8888
|
||||
filter: Nearest,Nearest
|
||||
repeat: none
|
||||
water
|
||||
xy: 0, 0
|
||||
size: 48, 64
|
||||
muck
|
||||
xy: 48,0
|
||||
size:48,64
|
||||
tree
|
||||
xy: 96,0
|
||||
size: 48,64
|
||||
tree2
|
||||
xy:144,0
|
||||
size:48,64
|
||||
dead_tree
|
||||
xy: 0,64
|
||||
size: 48,64
|
||||
dead_tree2
|
||||
xy: 48,64
|
||||
size: 48,64
|
||||
tree3
|
||||
xy: 96,64
|
||||
size: 48,64
|
||||
tree4
|
||||
xy:144,64
|
||||
size:48,64
|
||||
rock
|
||||
xy: 0, 128
|
||||
size: 48, 64
|
||||
rock2
|
||||
xy: 48, 128
|
||||
size: 48,64
|
||||
dead_tree3
|
||||
xy:96,128
|
||||
size:48,64
|
||||
|
After Width: | Height: | Size: 38 KiB |
@@ -0,0 +1,34 @@
|
||||
blue_structures.png
|
||||
size: 192,192
|
||||
format: RGBA8888
|
||||
filter: Nearest,Nearest
|
||||
repeat: none
|
||||
water
|
||||
xy: 0, 0
|
||||
size: 48, 64
|
||||
tree
|
||||
xy: 48,0
|
||||
size:48,64
|
||||
tree2
|
||||
xy: 96,0
|
||||
size: 48,64
|
||||
rock
|
||||
xy: 0,64
|
||||
size: 48,64
|
||||
rock2
|
||||
xy: 48,64
|
||||
size: 48,64
|
||||
pineapple
|
||||
xy: 96,64
|
||||
size: 48,64
|
||||
rock3
|
||||
xy: 0, 128
|
||||
size: 48, 64
|
||||
rock4
|
||||
xy: 48, 128
|
||||
size: 48,64
|
||||
dune
|
||||
xy:96,128
|
||||
size:48,64
|
||||
dune2
|
||||
xy:144,128
|
||||
|
After Width: | Height: | Size: 37 KiB |
@@ -0,0 +1,29 @@
|
||||
colorless_structures.png
|
||||
size: 144,192
|
||||
format: RGBA8888
|
||||
filter: Nearest,Nearest
|
||||
repeat: none
|
||||
hole
|
||||
xy: 0, 0
|
||||
size: 48, 64
|
||||
crater
|
||||
xy: 48,0
|
||||
size:48,64
|
||||
tree
|
||||
xy: 96,0
|
||||
size: 48,64
|
||||
tree2
|
||||
xy: 0,64
|
||||
size: 48,64
|
||||
tree3
|
||||
xy: 48,64
|
||||
size: 48,64
|
||||
tree4
|
||||
xy: 96,64
|
||||
size: 48,64
|
||||
rock
|
||||
xy: 0, 128
|
||||
size: 48, 64
|
||||
mountain
|
||||
xy: 48, 128
|
||||
size: 48,64
|
||||
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,41 @@
|
||||
green_structures.png
|
||||
size: 192,192
|
||||
format: RGBA8888
|
||||
filter: Nearest,Nearest
|
||||
repeat: none
|
||||
water
|
||||
xy: 0, 0
|
||||
size: 48, 64
|
||||
tree
|
||||
xy: 48,0
|
||||
size:48,64
|
||||
tree2
|
||||
xy: 96,0
|
||||
size: 48,64
|
||||
vine
|
||||
xy: 144,0
|
||||
size: 48,64
|
||||
tree3
|
||||
xy: 0,64
|
||||
size: 48,64
|
||||
tree4
|
||||
xy: 48,64
|
||||
size: 48,64
|
||||
tree5
|
||||
xy: 96,64
|
||||
size: 48,64
|
||||
tree6
|
||||
xy: 144, 64
|
||||
size: 48,64
|
||||
rock
|
||||
xy: 0, 128
|
||||
size: 48, 64
|
||||
mountain
|
||||
xy: 48, 128
|
||||
size: 48,64
|
||||
plant
|
||||
xy:96,128
|
||||
size:48,64
|
||||
bush
|
||||
xy:144,128
|
||||
size:48,64
|
||||
|
After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 508 B After Width: | Height: | Size: 508 B |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
BIN
forge-gui/res/adventure/common/world/structures/models/beach.png
Normal file
|
After Width: | Height: | Size: 192 B |
BIN
forge-gui/res/adventure/common/world/structures/models/black.png
Normal file
|
After Width: | Height: | Size: 261 B |
BIN
forge-gui/res/adventure/common/world/structures/models/blue.png
Normal file
|
After Width: | Height: | Size: 279 B |
|
After Width: | Height: | Size: 234 B |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 180 B |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 508 B After Width: | Height: | Size: 508 B |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
BIN
forge-gui/res/adventure/common/world/structures/models/green.png
Normal file
|
After Width: | Height: | Size: 318 B |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
BIN
forge-gui/res/adventure/common/world/structures/models/red.png
Normal file
|
After Width: | Height: | Size: 186 B |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 228 B |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
BIN
forge-gui/res/adventure/common/world/structures/models/white.png
Normal file
|
After Width: | Height: | Size: 132 B |