Merge branch 'Card-Forge:master' into master
@@ -48,10 +48,7 @@ import forge.util.collect.FCollection;
|
|||||||
import forge.util.collect.FCollectionView;
|
import forge.util.collect.FCollectionView;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -360,35 +357,41 @@ public class AiAttackController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this checks to make sure that the computer player doesn't lose when the human player attacks
|
// 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
|
//check for time walks
|
||||||
if (ai.getGame().getPhaseHandler().getNextTurn().equals(ai)) {
|
if (ai.getGame().getPhaseHandler().getNextTurn().equals(ai)) {
|
||||||
return attackers;
|
return potentialAttackers;
|
||||||
}
|
}
|
||||||
// no need to block (already holding mana to cast fog next turn)
|
// no need to block (already holding mana to cast fog next turn)
|
||||||
if (!AiCardMemory.isMemorySetEmpty(ai, AiCardMemory.MemorySet.CHOSEN_FOG_EFFECT)) {
|
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!
|
// Don't send the card that'll do the fog effect to attack, it's unsafe!
|
||||||
|
|
||||||
List<Card> toRemove = Lists.newArrayList();
|
List<Card> toRemove = Lists.newArrayList();
|
||||||
for (Card c : attackers) {
|
for (Card c : potentialAttackers) {
|
||||||
if (AiCardMemory.isRememberedCard(ai, c, AiCardMemory.MemorySet.CHOSEN_FOG_EFFECT)) {
|
if (AiCardMemory.isRememberedCard(ai, c, AiCardMemory.MemorySet.CHOSEN_FOG_EFFECT)) {
|
||||||
toRemove.add(c);
|
toRemove.add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attackers.removeAll(toRemove);
|
potentialAttackers.removeAll(toRemove);
|
||||||
return attackers;
|
return potentialAttackers;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Card> vigilantes = new ArrayList<>();
|
if (ai.isCardInPlay("Masako the Humorless")) {
|
||||||
for (final Card c : myList) {
|
|
||||||
if (c.getName().equals("Masako the Humorless")) {
|
|
||||||
// "Tapped creatures you control can block as though they were untapped."
|
// "Tapped creatures you control can block as though they were untapped."
|
||||||
return attackers;
|
return potentialAttackers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final CardCollection notNeededAsBlockers = new CardCollection(potentialAttackers);
|
||||||
|
|
||||||
|
final List<Card> vigilantes = new ArrayList<>();
|
||||||
|
for (final Card c : Iterables.concat(currentAttackers, potentialAttackers)) {
|
||||||
// no need to block if an effect is in play which untaps all creatures
|
// no need to block if an effect is in play which untaps all creatures
|
||||||
// (pseudo-Vigilance akin to Awakening or Prophet of Kruphix)
|
// (pseudo-Vigilance akin to Awakening or Prophet of Kruphix)
|
||||||
if (c.hasKeyword(Keyword.VIGILANCE) || ComputerUtilCard.willUntap(ai, c)) {
|
if (c.hasKeyword(Keyword.VIGILANCE) || ComputerUtilCard.willUntap(ai, c)) {
|
||||||
vigilantes.add(c);
|
vigilantes.add(c);
|
||||||
|
} else if (currentAttackers.contains(c)) {
|
||||||
|
// already attacking so can't block
|
||||||
|
notNeededAsBlockers.add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// reduce the search space
|
// 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
|
// 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()) {
|
if (!blockers.isEmpty()) {
|
||||||
notNeededAsBlockers.removeAll(blockers);
|
notNeededAsBlockers.removeAll(blockers);
|
||||||
@@ -476,12 +477,15 @@ public class AiAttackController {
|
|||||||
// these creatures will be available to block anyway
|
// these creatures will be available to block anyway
|
||||||
notNeededAsBlockers.addAll(vigilantes);
|
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
|
// 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)
|
// (human will get an extra first attack with a creature that untaps)
|
||||||
// In addition, if the computer guesses it needs no blockers, make sure
|
// In addition, if the computer guesses it needs no blockers, make sure
|
||||||
// that it won't be surprised by Exalted
|
// that it won't be surprised by Exalted
|
||||||
final int humanExaltedBonus = defendingOpponent.countExaltedBonus();
|
final int humanExaltedBonus = defendingOpponent.countExaltedBonus();
|
||||||
int blockersNeeded = attackers.size() - notNeededAsBlockers.size();
|
int blockersNeeded = potentialAttackers.size() - notNeededAsBlockers.size();
|
||||||
|
|
||||||
if (humanExaltedBonus > 0) {
|
if (humanExaltedBonus > 0) {
|
||||||
final boolean finestHour = defendingOpponent.isCardInPlay("Finest Hour");
|
final boolean finestHour = defendingOpponent.isCardInPlay("Finest Hour");
|
||||||
@@ -511,6 +515,88 @@ public class AiAttackController {
|
|||||||
return notNeededAsBlockers;
|
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() {
|
private boolean doAssault() {
|
||||||
if (ai.isCardInPlay("Beastmaster Ascension") && this.attackers.size() > 1) {
|
if (ai.isCardInPlay("Beastmaster Ascension") && this.attackers.size() > 1) {
|
||||||
final CardCollectionView beastions = ai.getCardsIn(ZoneType.Battlefield, "Beastmaster Ascension");
|
final CardCollectionView beastions = ai.getCardsIn(ZoneType.Battlefield, "Beastmaster Ascension");
|
||||||
@@ -1199,7 +1285,7 @@ public class AiAttackController {
|
|||||||
if ( LOG_AI_ATTACKS )
|
if ( LOG_AI_ATTACKS )
|
||||||
System.out.println("Normal attack");
|
System.out.println("Normal attack");
|
||||||
|
|
||||||
attackersLeft = notNeededAsBlockers(attackersLeft);
|
attackersLeft = notNeededAsBlockers(combat.getAttackers(), attackersLeft);
|
||||||
attackersLeft = sortAttackers(attackersLeft);
|
attackersLeft = sortAttackers(attackersLeft);
|
||||||
|
|
||||||
if ( LOG_AI_ATTACKS )
|
if ( LOG_AI_ATTACKS )
|
||||||
|
|||||||
@@ -17,11 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package forge.ai;
|
package forge.ai;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
@@ -36,6 +32,7 @@ import forge.game.card.CardCollectionView;
|
|||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
import forge.game.card.CardPredicates;
|
import forge.game.card.CardPredicates;
|
||||||
import forge.game.card.CounterEnumType;
|
import forge.game.card.CounterEnumType;
|
||||||
|
import forge.game.combat.AttackingBand;
|
||||||
import forge.game.combat.Combat;
|
import forge.game.combat.Combat;
|
||||||
import forge.game.combat.CombatUtil;
|
import forge.game.combat.CombatUtil;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
@@ -770,14 +767,44 @@ public class AiBlockController {
|
|||||||
tramplingAttackers = CardLists.filter(tramplingAttackers, Predicates.not(changesPTWhenBlocked(true)));
|
tramplingAttackers = CardLists.filter(tramplingAttackers, Predicates.not(changesPTWhenBlocked(true)));
|
||||||
|
|
||||||
for (final Card attacker : tramplingAttackers) {
|
for (final Card attacker : tramplingAttackers) {
|
||||||
|
boolean staticAssignCombatDamageAsUnblocked = StaticAbilityAssignCombatDamageAsUnblocked.assignCombatDamageAsUnblocked(attacker);
|
||||||
|
|
||||||
if (CombatUtil.getMinNumBlockersForAttacker(attacker, combat.getDefenderPlayerByAttacker(attacker)) > combat.getBlockers(attacker).size()
|
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.")) {
|
|| attacker.hasKeyword("CARDNAME can't be blocked unless all creatures defending player controls block it.")) {
|
||||||
continue;
|
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 = getPossibleBlockers(combat, attacker, blockersLeft, false);
|
||||||
chumpBlockers.removeAll(combat.getBlockers(attacker));
|
chumpBlockers.removeAll(combat.getBlockers(attacker));
|
||||||
|
|
||||||
|
// See if there's a Banding blocker that can tank the damage
|
||||||
|
for (final Card blocker : chumpBlockers) {
|
||||||
|
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) {
|
for (final Card blocker : chumpBlockers) {
|
||||||
// Add an additional blocker if the current blockers are not
|
// Add an additional blocker if the current blockers are not
|
||||||
// enough and the new one would suck some of the damage
|
// enough and the new one would suck some of the damage
|
||||||
@@ -789,6 +816,7 @@ public class AiBlockController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Support blockers not destroying the attacker with more blockers to try to kill the attacker */
|
/** Support blockers not destroying the attacker with more blockers to try to kill the attacker */
|
||||||
private void reinforceBlockersToKill(final Combat combat) {
|
private void reinforceBlockersToKill(final Combat combat) {
|
||||||
|
|||||||
@@ -1304,6 +1304,9 @@ public class AiController {
|
|||||||
AiAttackController aiAtk = new AiAttackController(attacker);
|
AiAttackController aiAtk = new AiAttackController(attacker);
|
||||||
lastAttackAggression = aiAtk.declareAttackers(combat);
|
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 invalid: just try an attack declaration that we know to be legal
|
||||||
if (!CombatUtil.validateAttackers(combat)) {
|
if (!CombatUtil.validateAttackers(combat)) {
|
||||||
combat.clearAttackers();
|
combat.clearAttackers();
|
||||||
@@ -1618,8 +1621,7 @@ public class AiController {
|
|||||||
AiPlayDecision opinion = canPlayAndPayFor(sa);
|
AiPlayDecision opinion = canPlayAndPayFor(sa);
|
||||||
|
|
||||||
// reset LastStateBattlefield
|
// reset LastStateBattlefield
|
||||||
sa.setLastStateBattlefield(CardCollection.EMPTY);
|
sa.clearLastState();
|
||||||
sa.setLastStateGraveyard(CardCollection.EMPTY);
|
|
||||||
// PhaseHandler ph = game.getPhaseHandler();
|
// 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());
|
// 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();
|
final Player opp = ai.getWeakestOpponent();
|
||||||
Card pumped = getPumpedCreature(ai, sa, c, toughness, power, keywords);
|
Card pumped = getPumpedCreature(ai, sa, c, toughness, power, keywords);
|
||||||
List<Card> oppCreatures = opp.getCreaturesInPlay();
|
List<Card> oppCreatures = opp.getCreaturesInPlay();
|
||||||
|
|||||||
@@ -17,26 +17,17 @@
|
|||||||
*/
|
*/
|
||||||
package forge.ai;
|
package forge.ai;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameEntity;
|
import forge.game.GameEntity;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.*;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.combat.AttackingBand;
|
||||||
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.combat.Combat;
|
import forge.game.combat.Combat;
|
||||||
import forge.game.combat.CombatUtil;
|
import forge.game.combat.CombatUtil;
|
||||||
import forge.game.cost.CostPayment;
|
import forge.game.cost.CostPayment;
|
||||||
@@ -57,6 +48,9 @@ import forge.util.MyRandom;
|
|||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
import forge.util.collect.FCollection;
|
import forge.util.collect.FCollection;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@@ -2023,6 +2017,8 @@ public class ComputerUtilCombat {
|
|||||||
* distributeAIDamage.
|
* distributeAIDamage.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
|
* @param self
|
||||||
|
* a {@link forge.game.player.Player} object.
|
||||||
* @param attacker
|
* @param attacker
|
||||||
* a {@link forge.game.card.Card} object.
|
* a {@link forge.game.card.Card} object.
|
||||||
* @param block
|
* @param block
|
||||||
@@ -2031,16 +2027,20 @@ public class ComputerUtilCombat {
|
|||||||
* @param defender
|
* @param defender
|
||||||
* @param overrideOrder overriding combatant order
|
* @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) {
|
public static Map<Card, Integer> distributeAIDamage(final Player self, 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
|
|
||||||
Map<Card, Integer> damageMap = Maps.newHashMap();
|
Map<Card, Integer> damageMap = Maps.newHashMap();
|
||||||
Combat combat = attacker.getGame().getCombat();
|
Combat combat = attacker.getGame().getCombat();
|
||||||
|
|
||||||
boolean isAttacking = defender != null;
|
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);
|
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
|
// 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
|
// to assign those without trample first so we can maximize the damage to the defender
|
||||||
for (final Card c : remaining) {
|
for (final Card c : remaining) {
|
||||||
@@ -2061,7 +2061,7 @@ public class ComputerUtilCombat {
|
|||||||
final Card blocker = block.getFirst();
|
final Card blocker = block.getFirst();
|
||||||
int dmgToBlocker = dmgCanDeal;
|
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);
|
dmgToBlocker = getEnoughDamageToKill(blocker, dmgCanDeal, attacker, true);
|
||||||
|
|
||||||
if (dmgCanDeal < dmgToBlocker) {
|
if (dmgCanDeal < dmgToBlocker) {
|
||||||
@@ -2077,7 +2077,7 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
damageMap.put(blocker, dmgToBlocker);
|
damageMap.put(blocker, dmgToBlocker);
|
||||||
} // 1 blocker
|
} // 1 blocker
|
||||||
else {
|
else if (!aiDistributesBandingDmg) {
|
||||||
// Does the attacker deal lethal damage to all blockers
|
// Does the attacker deal lethal damage to all blockers
|
||||||
//Blocking Order now determined after declare blockers
|
//Blocking Order now determined after declare blockers
|
||||||
Card lastBlocker = null;
|
Card lastBlocker = null;
|
||||||
@@ -2098,13 +2098,26 @@ public class ComputerUtilCombat {
|
|||||||
}
|
}
|
||||||
} // for
|
} // 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
|
if (hasTrample && isAttacking) // if you have trample, deal damage to defending entity
|
||||||
damageMap.put(null, dmgCanDeal);
|
damageMap.put(null, dmgCanDeal);
|
||||||
else if (lastBlocker != null) { // otherwise flush it into last blocker
|
else if (lastBlocker != null) { // otherwise flush it into last blocker
|
||||||
damageMap.put(lastBlocker, dmgCanDeal + damageMap.get(lastBlocker));
|
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;
|
return damageMap;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -962,7 +962,12 @@ public class ComputerUtilMana {
|
|||||||
ManaCostShard toPay, SpellAbility saPayment) {
|
ManaCostShard toPay, SpellAbility saPayment) {
|
||||||
AbilityManaPart m = saPayment.getManaPart();
|
AbilityManaPart m = saPayment.getManaPart();
|
||||||
if (m.isComboMana()) {
|
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);
|
getComboManaChoice(ai, saPayment, sa, cost);
|
||||||
}
|
}
|
||||||
else if (saPayment.getApi() == ApiType.ManaReflected) {
|
else if (saPayment.getApi() == ApiType.ManaReflected) {
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Card, Integer> assignCombatDamage(Card attacker, CardCollectionView blockers, CardCollectionView remaining, int damageDealt, GameEntity defender, boolean overrideOrder) {
|
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
|
@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
|
// Guilty Conscience
|
||||||
public static class GuiltyConscience {
|
public static class GuiltyConscience {
|
||||||
public static Card getBestAttachTarget(final Player ai, final SpellAbility sa, final List<Card> list) {
|
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
|
// Don't steal something if I can't Attack without, or prevent it from blocking at least
|
||||||
if (lose.contains("EOT")
|
if (lose.contains("EOT")
|
||||||
&& ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
&& game.getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
||||||
&& !sa.isTrigger()) {
|
&& !sa.isTrigger()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ public class CounterAi extends SpellAbilityAi {
|
|||||||
String logic = sa.getParam("AILogic");
|
String logic = sa.getParam("AILogic");
|
||||||
if ("Never".equals(logic)) {
|
if ("Never".equals(logic)) {
|
||||||
return false;
|
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));
|
int minCMC = Integer.parseInt(logic.substring(7));
|
||||||
if (tgtCMC < minCMC) {
|
if (tgtCMC < minCMC) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ public class DebuffAi extends SpellAbilityAi {
|
|||||||
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
||||||
|| !game.getStack().isEmpty()) {
|
|| !game.getStack().isEmpty()) {
|
||||||
// Instant-speed pumps should not be cast outside of combat when the
|
// Instant-speed pumps should not be cast outside of combat when the
|
||||||
// stack is empty
|
// stack is empty, unless there are specific activation phase requirements
|
||||||
if (!SpellAbilityAi.isSorcerySpeed(sa, ai)) {
|
if (!SpellAbilityAi.isSorcerySpeed(sa, ai) && !sa.hasParam("ActivationPhases")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,7 @@ package forge.ai.ability;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import forge.ai.ComputerUtil;
|
import forge.ai.*;
|
||||||
import forge.ai.ComputerUtilAbility;
|
|
||||||
import forge.ai.ComputerUtilCard;
|
|
||||||
import forge.ai.ComputerUtilCombat;
|
|
||||||
import forge.ai.SpellAbilityAi;
|
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -32,9 +28,13 @@ public class FightAi extends SpellAbilityAi {
|
|||||||
sa.resetTargets();
|
sa.resetTargets();
|
||||||
final Card source = sa.getHostCard();
|
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()) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ public class FightAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
|
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
|
||||||
if (canPlayAI(ai, sa)) {
|
if (checkApiLogic(ai, sa)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!mandatory) {
|
if (!mandatory) {
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ public class GameAction {
|
|||||||
|
|
||||||
// Don't copy Tokens, copy only cards leaving the battlefield
|
// Don't copy Tokens, copy only cards leaving the battlefield
|
||||||
// and returning to hand (to recreate their spell ability information)
|
// and returning to hand (to recreate their spell ability information)
|
||||||
if (suppress || toBattlefield) {
|
if (toBattlefield || (suppress && zoneTo.getZoneType().isHidden())) {
|
||||||
copied = c;
|
copied = c;
|
||||||
|
|
||||||
if (lastKnownInfo == null) {
|
if (lastKnownInfo == null) {
|
||||||
@@ -295,7 +295,6 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
copied.setUnearthed(c.isUnearthed());
|
copied.setUnearthed(c.isUnearthed());
|
||||||
copied.setTapped(false);
|
|
||||||
|
|
||||||
// need to copy counters when card enters another zone than hand or library
|
// 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.") &&
|
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
|
// reset timestamp in changezone effects so they have same timestamp if ETB simultaneously
|
||||||
copied.setTimestamp(game.getNextTimestamp());
|
copied.setTimestamp(game.getNextTimestamp());
|
||||||
}
|
}
|
||||||
@@ -600,7 +599,7 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// only now that the LKI preserved it
|
// only now that the LKI preserved it
|
||||||
if (!zoneTo.is(ZoneType.Exile) && !zoneTo.is(ZoneType.Stack)) {
|
if (!zoneTo.is(ZoneType.Stack)) {
|
||||||
c.cleanupExiledWith();
|
c.cleanupExiledWith();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,7 +635,6 @@ public class GameAction {
|
|||||||
}
|
}
|
||||||
game.getTriggerHandler().runTrigger(TriggerType.ChangesController, runParams2, false);
|
game.getTriggerHandler().runTrigger(TriggerType.ChangesController, runParams2, false);
|
||||||
}
|
}
|
||||||
// AllZone.getStack().chooseOrderOfSimultaneousStackEntryAll();
|
|
||||||
|
|
||||||
if (suppress) {
|
if (suppress) {
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
@@ -923,10 +921,6 @@ public class GameAction {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public final Card exile(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
|
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 Zone origin = c.getZone();
|
||||||
final PlayerZone removed = c.getOwner().getZone(ZoneType.Exile);
|
final PlayerZone removed = c.getOwner().getZone(ZoneType.Exile);
|
||||||
final Card copied = moveTo(removed, c, cause, params);
|
final Card copied = moveTo(removed, c, cause, params);
|
||||||
|
|||||||
@@ -561,9 +561,6 @@ public class AbilityUtils {
|
|||||||
}
|
}
|
||||||
} else if (calcX[0].equals("OriginalHost")) {
|
} else if (calcX[0].equals("OriginalHost")) {
|
||||||
val = xCount(ability.getOriginalHost(), calcX[1], ability);
|
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")) {
|
} else if (calcX[0].startsWith("ExiledWith")) {
|
||||||
val = handlePaid(card.getExiledCards(), calcX[1], card, ability);
|
val = handlePaid(card.getExiledCards(), calcX[1], card, ability);
|
||||||
} else if (calcX[0].startsWith("Convoked")) {
|
} else if (calcX[0].startsWith("Convoked")) {
|
||||||
|
|||||||
@@ -393,11 +393,16 @@ public abstract class SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void addForgetOnMovedTrigger(final Card card, final String zone) {
|
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);
|
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(parsedTrigger);
|
||||||
|
card.addTrigger(parsedTrigger2);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void addForgetOnCastTrigger(final Card card) {
|
protected static void addForgetOnCastTrigger(final Card card) {
|
||||||
|
|||||||
@@ -122,9 +122,8 @@ public class SacrificeEffect extends SpellAbilityEffect {
|
|||||||
String [] msgArray = msg.split(" & ");
|
String [] msgArray = msg.split(" & ");
|
||||||
List<CardCollection> validTargetsList = new ArrayList<>(validArray.length);
|
List<CardCollection> validTargetsList = new ArrayList<>(validArray.length);
|
||||||
for (String subValid : validArray) {
|
for (String subValid : validArray) {
|
||||||
CardCollectionView validTargets = AbilityUtils.filterListByType(battlefield, subValid, sa);
|
CardCollection validTargets = CardLists.filter(AbilityUtils.filterListByType(battlefield, subValid, sa), CardPredicates.canBeSacrificedBy(sa, true));
|
||||||
validTargets = CardLists.filter(validTargets, CardPredicates.canBeSacrificedBy(sa, true));
|
validTargetsList.add(validTargets);
|
||||||
validTargetsList.add(new CardCollection(validTargets));
|
|
||||||
}
|
}
|
||||||
CardCollection chosenCards = new CardCollection();
|
CardCollection chosenCards = new CardCollection();
|
||||||
for (int i = 0; i < validArray.length; ++i) {
|
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,
|
public static List<String> sharedKeywords(final Iterable<String> kw, final String[] restrictions,
|
||||||
final Iterable<ZoneType> zones, final Card host, CardTraitBase ctb) {
|
final Iterable<ZoneType> zones, final Card host, CardTraitBase ctb) {
|
||||||
final List<String> filteredkw = Lists.newArrayList();
|
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);
|
CardCollectionView cardlist = p.getGame().getCardsIn(zones);
|
||||||
final Set<String> landkw = Sets.newHashSet();
|
final Set<String> landkw = Sets.newHashSet();
|
||||||
final Set<String> protectionkw = Sets.newHashSet();
|
final Set<String> protectionkw = Sets.newHashSet();
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package forge.game.combat;
|
package forge.game.combat;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
import forge.game.keyword.Keyword;
|
import forge.game.keyword.Keyword;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class AttackingBand {
|
public class AttackingBand {
|
||||||
private CardCollection attackers = new CardCollection();
|
private CardCollection attackers = new CardCollection();
|
||||||
private Boolean blocked = null; // even if all blockers were killed before FS or CD, band remains blocked
|
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 addAttacker(Card card) { attackers.add(card); }
|
||||||
public void removeAttacker(Card card) { attackers.remove(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()) {
|
if (band.isEmpty()) {
|
||||||
// An empty band is not a valid band
|
// An empty band is not a valid band
|
||||||
return false;
|
return false;
|
||||||
@@ -64,7 +63,7 @@ public class AttackingBand {
|
|||||||
|
|
||||||
public boolean canJoinBand(Card card) {
|
public boolean canJoinBand(Card card) {
|
||||||
// Trying to join an existing band, attackers should be non-empty and card should exist
|
// 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) {
|
if (card != null) {
|
||||||
newBand.add(card);
|
newBand.add(card);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,7 +327,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
|
|
||||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
activeScheme = getZone(ZoneType.SchemeDeck).get(0);
|
activeScheme = getZone(ZoneType.SchemeDeck).get(0);
|
||||||
// gameAction moveTo ?
|
|
||||||
game.getAction().moveTo(ZoneType.Command, activeScheme, null, moveParams);
|
game.getAction().moveTo(ZoneType.Command, activeScheme, null, moveParams);
|
||||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
|
|
||||||
@@ -800,7 +799,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
restDamage = 2;
|
restDamage = 2;
|
||||||
}
|
}
|
||||||
} else if (c.getName().equals("Elderscale Wurm")) {
|
} 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;
|
restDamage = getLife() - 7;
|
||||||
if (restDamage < 0) {
|
if (restDamage < 0) {
|
||||||
restDamage = 0;
|
restDamage = 0;
|
||||||
@@ -3268,9 +3267,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final TriggerHandler triggerHandler = game.getTriggerHandler();
|
final TriggerHandler triggerHandler = game.getTriggerHandler();
|
||||||
triggerHandler.suppressMode(TriggerType.ChangesZone);
|
com.add(initiativeEffect);
|
||||||
game.getAction().moveTo(ZoneType.Command, initiativeEffect, null, null);
|
|
||||||
triggerHandler.clearSuppression(TriggerType.ChangesZone);
|
|
||||||
triggerHandler.clearActiveTriggers(initiativeEffect, null);
|
triggerHandler.clearActiveTriggers(initiativeEffect, null);
|
||||||
triggerHandler.registerActiveTrigger(initiativeEffect, false);
|
triggerHandler.registerActiveTrigger(initiativeEffect, false);
|
||||||
|
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ public class ReplacementHandler {
|
|||||||
chosenRE.setHasRun(true);
|
chosenRE.setHasRun(true);
|
||||||
hasRun.add(chosenRE);
|
hasRun.add(chosenRE);
|
||||||
chosenRE.setOtherChoices(possibleReplacers);
|
chosenRE.setOtherChoices(possibleReplacers);
|
||||||
ReplacementResult res = executeReplacement(runParams, chosenRE, decider, game);
|
ReplacementResult res = executeReplacement(runParams, chosenRE, decider);
|
||||||
if (res == ReplacementResult.NotReplaced) {
|
if (res == ReplacementResult.NotReplaced) {
|
||||||
if (!possibleReplacers.isEmpty()) {
|
if (!possibleReplacers.isEmpty()) {
|
||||||
res = run(event, runParams);
|
res = run(event, runParams);
|
||||||
@@ -287,8 +287,7 @@ public class ReplacementHandler {
|
|||||||
* the replacement effect to run
|
* the replacement effect to run
|
||||||
*/
|
*/
|
||||||
private ReplacementResult executeReplacement(final Map<AbilityKey, Object> runParams,
|
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;
|
SpellAbility effectSA = null;
|
||||||
|
|
||||||
Card host = replacementEffect.getHostCard();
|
Card host = replacementEffect.getHostCard();
|
||||||
@@ -441,7 +440,7 @@ public class ReplacementHandler {
|
|||||||
int damage = (int) runParams.get(AbilityKey.DamageAmount);
|
int damage = (int) runParams.get(AbilityKey.DamageAmount);
|
||||||
Map<String, String> mapParams = re.getMapParams();
|
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);
|
GameEntity newTarget = (GameEntity) runParams.get(AbilityKey.Affected);
|
||||||
int newDamage = (int) runParams.get(AbilityKey.DamageAmount);
|
int newDamage = (int) runParams.get(AbilityKey.DamageAmount);
|
||||||
|
|
||||||
|
|||||||
@@ -201,6 +201,11 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
this.lastStateGraveyard = new CardCollection(lastStateGraveyard);
|
this.lastStateGraveyard = new CardCollection(lastStateGraveyard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearLastState() {
|
||||||
|
lastStateBattlefield = null;
|
||||||
|
lastStateGraveyard = null;
|
||||||
|
}
|
||||||
|
|
||||||
protected SpellAbility(final Card iSourceCard, final Cost toPay) {
|
protected SpellAbility(final Card iSourceCard, final Cost toPay) {
|
||||||
this(iSourceCard, toPay, null);
|
this(iSourceCard, toPay, null);
|
||||||
}
|
}
|
||||||
@@ -828,10 +833,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
if (isActivatedAbility()) {
|
if (isActivatedAbility()) {
|
||||||
setXManaCostPaid(null);
|
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
|
// 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")) {
|
if (params.containsKey("ConditionTargetsSingleTarget")) {
|
||||||
this.setTargetsSingleTarget(true);
|
this.setTargetsSingleTarget(true);
|
||||||
}
|
}
|
||||||
} // setConditions
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
|||||||
this.setClassLevelOperator(params.get("ClassLevel").substring(0, 2));
|
this.setClassLevelOperator(params.get("ClassLevel").substring(0, 2));
|
||||||
this.setClassLevel(params.get("ClassLevel").substring(2));
|
this.setClassLevel(params.get("ClassLevel").substring(2));
|
||||||
}
|
}
|
||||||
} // end setRestrictions()
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -528,9 +528,6 @@ public class TriggerHandler {
|
|||||||
sa = sa.copy(host, controller, false);
|
sa = sa.copy(host, controller, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
|
||||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
|
||||||
|
|
||||||
sa.setTrigger(regtrig);
|
sa.setTrigger(regtrig);
|
||||||
sa.setSourceTrigger(regtrig.getId());
|
sa.setSourceTrigger(regtrig.getId());
|
||||||
regtrig.setTriggeringObjects(sa, runParams);
|
regtrig.setTriggeringObjects(sa, runParams);
|
||||||
@@ -565,7 +562,6 @@ public class TriggerHandler {
|
|||||||
//wrapperAbility.setDescription(wrapperAbility.getStackDescription());
|
//wrapperAbility.setDescription(wrapperAbility.getStackDescription());
|
||||||
//wrapperAbility.setDescription(wrapperAbility.toUnsuppressedString());
|
//wrapperAbility.setDescription(wrapperAbility.toUnsuppressedString());
|
||||||
|
|
||||||
wrapperAbility.setLastStateBattlefield(game.getLastStateBattlefield());
|
|
||||||
if (regtrig.isStatic()) {
|
if (regtrig.isStatic()) {
|
||||||
wrapperAbility.getActivatingPlayer().getController().playTrigger(host, wrapperAbility, isMandatory);
|
wrapperAbility.getActivatingPlayer().getController().playTrigger(host, wrapperAbility, isMandatory);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -279,6 +279,7 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
|
|||||||
sa.setTriggeringObject(AbilityKey.LifeAmount, castSA.getAmountLifePaid());
|
sa.setTriggeringObject(AbilityKey.LifeAmount, castSA.getAmountLifePaid());
|
||||||
sa.setTriggeringObjectsFrom(
|
sa.setTriggeringObjectsFrom(
|
||||||
runParams,
|
runParams,
|
||||||
|
AbilityKey.CardLKI,
|
||||||
AbilityKey.Player,
|
AbilityKey.Player,
|
||||||
AbilityKey.Activator,
|
AbilityKey.Activator,
|
||||||
AbilityKey.CurrentStormCount,
|
AbilityKey.CurrentStormCount,
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ import forge.game.ability.AbilityKey;
|
|||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
|
||||||
import forge.game.card.CardUtil;
|
import forge.game.card.CardUtil;
|
||||||
import forge.game.event.EventValueChangeType;
|
import forge.game.event.EventValueChangeType;
|
||||||
import forge.game.event.GameEventCardStatsChanged;
|
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.
|
// Copied spells aren't cast per se so triggers shouldn't run for them.
|
||||||
Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(sp.getHostCard().getController());
|
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.Cost, sp.getPayCosts());
|
||||||
runParams.put(AbilityKey.Activator, sp.getActivatingPlayer());
|
runParams.put(AbilityKey.Activator, sp.getActivatingPlayer());
|
||||||
runParams.put(AbilityKey.CastSA, si.getSpellAbility(true));
|
runParams.put(AbilityKey.CastSA, si.getSpellAbility(true));
|
||||||
@@ -462,10 +469,6 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
|
|
||||||
GameActionUtil.checkStaticAfterPaying(sp.getHostCard());
|
GameActionUtil.checkStaticAfterPaying(sp.getHostCard());
|
||||||
|
|
||||||
if (sp.isSpell() && !sp.isCopied()) {
|
|
||||||
thisTurnCast.add(CardUtil.getLKICopy(sp.getHostCard()));
|
|
||||||
sp.getActivatingPlayer().addSpellCastThisTurn();
|
|
||||||
}
|
|
||||||
if (sp.isActivatedAbility() && sp.isPwAbility()) {
|
if (sp.isActivatedAbility() && sp.isPwAbility()) {
|
||||||
sp.getActivatingPlayer().setActivateLoyaltyAbilityThisTurn(true);
|
sp.getActivatingPlayer().setActivateLoyaltyAbilityThisTurn(true);
|
||||||
}
|
}
|
||||||
@@ -694,8 +697,6 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
|||||||
frozenStack.remove(si);
|
frozenStack.remove(si);
|
||||||
game.updateStackForView();
|
game.updateStackForView();
|
||||||
SpellAbility sa = si.getSpellAbility(false);
|
SpellAbility sa = si.getSpellAbility(false);
|
||||||
sa.setLastStateBattlefield(CardCollection.EMPTY);
|
|
||||||
sa.setLastStateGraveyard(CardCollection.EMPTY);
|
|
||||||
game.fireEvent(new GameEventSpellRemovedFromStack(sa));
|
game.fireEvent(new GameEventSpellRemovedFromStack(sa));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -490,12 +490,17 @@ public class GameHUD extends Stage {
|
|||||||
private void setAudio(MusicPlaylist playlist) {
|
private void setAudio(MusicPlaylist playlist) {
|
||||||
if (playlist.equals(currentAudioPlaylist))
|
if (playlist.equals(currentAudioPlaylist))
|
||||||
return;
|
return;
|
||||||
|
System.out.println("Playlist: "+playlist);
|
||||||
unloadAudio();
|
unloadAudio();
|
||||||
|
System.out.println("Playlist: "+playlist);
|
||||||
audio = getMusic(playlist);
|
audio = getMusic(playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<FileHandle, Music> getMusic(MusicPlaylist 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);
|
Music music = Forge.getAssets().getMusic(file);
|
||||||
if (music != null) {
|
if (music != null) {
|
||||||
currentAudioPlaylist = playlist;
|
currentAudioPlaylist = playlist;
|
||||||
@@ -776,7 +781,7 @@ public class GameHUD extends Stage {
|
|||||||
changeBGM(MusicPlaylist.WHITE);
|
changeBGM(MusicPlaylist.WHITE);
|
||||||
break;
|
break;
|
||||||
case "waste":
|
case "waste":
|
||||||
changeBGM(MusicPlaylist.MENUS);
|
changeBGM(MusicPlaylist.COLORLESS);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"maxRoadDistance": 1000,
|
"maxRoadDistance": 1000,
|
||||||
"biomesNames": [
|
"biomesNames": [
|
||||||
"world/biomes/base.json",
|
"world/biomes/base.json",
|
||||||
"world/biomes/waste.json",
|
"world/biomes/colorless.json",
|
||||||
"world/biomes/white.json",
|
"world/biomes/white.json",
|
||||||
"world/biomes/blue.json",
|
"world/biomes/blue.json",
|
||||||
"world/biomes/black.json",
|
"world/biomes/black.json",
|
||||||
|
|||||||
BIN
forge-gui/res/adventure/common/music/menus/menu1.mp3
Normal file
@@ -23,11 +23,8 @@
|
|||||||
"height": 0.7,
|
"height": 0.7,
|
||||||
"color": "110903",
|
"color": "110903",
|
||||||
"spriteNames": [
|
"spriteNames": [
|
||||||
"SwampTree",
|
|
||||||
"SwampTree2",
|
|
||||||
"DarkGras",
|
"DarkGras",
|
||||||
"Skull",
|
"Skull",
|
||||||
"SwampRock",
|
|
||||||
"DarkWood",
|
"DarkWood",
|
||||||
"Reed",
|
"Reed",
|
||||||
"Waterlily",
|
"Waterlily",
|
||||||
@@ -120,22 +117,46 @@
|
|||||||
"N": 2,
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/black_structures.atlas",
|
||||||
"sourcePath": "world/models/swamp_forest.png",
|
"sourcePath": "world/structures/models/black.png",
|
||||||
"maskPath": "world/masks/ring.png",
|
"maskPath": "world/structures/masks/ring.png",
|
||||||
"height": 0.5,
|
"height": 0.5,
|
||||||
"width": 0.5,
|
"width": 0.5,
|
||||||
"symmetry": 8,
|
"symmetry": 8,
|
||||||
"periodicOutput": false,
|
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "swamp_forest",
|
"name": "water",
|
||||||
"color": "007000",
|
"color": "00ffff",
|
||||||
"collision": true
|
"collision": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "swamp_water",
|
"name": "tree",
|
||||||
"color": "005050",
|
"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
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -144,27 +165,41 @@
|
|||||||
"N": 2,
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/black_structures.atlas",
|
||||||
"sourcePath": "world/models/swamp_ruins.png",
|
"sourcePath": "world/structures/models/black.png",
|
||||||
"maskPath": "world/masks/circle.png",
|
"maskPath": "world/structures/masks/circle.png",
|
||||||
"height": 0.20000002,
|
"height": 0.20000002,
|
||||||
"width": 0.20000002,
|
"width": 0.20000002,
|
||||||
"symmetry": 1,
|
"symmetry": 8,
|
||||||
"periodicOutput": false,
|
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "deep_swamp",
|
"name": "muck",
|
||||||
"color": "002000",
|
"color": "00ffff",
|
||||||
"collision": true
|
"collision": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "structure",
|
"name": "dead_tree",
|
||||||
"color": "505050",
|
"color": "004000",
|
||||||
"collision": true
|
"collision": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "swamp_forest2",
|
"name": "dead_tree2",
|
||||||
"color": "007000",
|
"color": "008000",
|
||||||
|
"collision": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dead_tree3",
|
||||||
|
"color": "ff00ff",
|
||||||
|
"collision": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rock",
|
||||||
|
"color": "808080",
|
||||||
|
"collision": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "rock2",
|
||||||
|
"color": "ff0000",
|
||||||
"collision": true
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -23,8 +23,6 @@
|
|||||||
"height": 0.7,
|
"height": 0.7,
|
||||||
"color": "10a2e0",
|
"color": "10a2e0",
|
||||||
"spriteNames": [
|
"spriteNames": [
|
||||||
"IslandTree",
|
|
||||||
"Coral",
|
|
||||||
"Shell"
|
"Shell"
|
||||||
],
|
],
|
||||||
"enemies": [
|
"enemies": [
|
||||||
@@ -108,47 +106,93 @@
|
|||||||
],
|
],
|
||||||
"structures": [
|
"structures": [
|
||||||
{
|
{
|
||||||
|
"N":2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/blue_structures.atlas",
|
||||||
"sourcePath": "world/models/water.png",
|
"sourcePath": "world/structures/models/blue.png",
|
||||||
"maskPath": "world/masks/circle.png",
|
"maskPath": "world/structures/masks/circle.png",
|
||||||
"height": 0.20000002,
|
"height": 0.1,
|
||||||
"width": 0.20000002,
|
"width": 0.1,
|
||||||
"symmetry": 8,
|
"symmetry": 8,
|
||||||
"periodicOutput": false,
|
"periodicOutput": false,
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "water",
|
"name": "water",
|
||||||
"color": "0070a0",
|
"color": "00ffff",
|
||||||
"collision": true
|
"collision": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "island_forest",
|
"name": "tree",
|
||||||
"color": "00a000",
|
"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
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/blue_structures.atlas",
|
||||||
"sourcePath": "world/models/island_forest.png",
|
"sourcePath": "world/structures/models/beach.png",
|
||||||
"maskPath": "world/masks/ring.png",
|
"maskPath": "world/structures/masks/ring.png",
|
||||||
"height": 0.5,
|
"height": 0.5,
|
||||||
"width": 0.5,
|
"width": 0.5,
|
||||||
"symmetry": 8,
|
"symmetry": 8,
|
||||||
"periodicOutput": false,
|
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "water",
|
"name": "water",
|
||||||
"color": "0070a0",
|
"color": "00ffff",
|
||||||
"collision": true
|
"collision": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "island_forest",
|
"name": "tree",
|
||||||
"color": "00a000",
|
"color": "00ff00",
|
||||||
|
"collision": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tree2",
|
||||||
|
"color": "008000",
|
||||||
|
"collision": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dune",
|
||||||
|
"color": "ff8000",
|
||||||
|
"collision": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dune2",
|
||||||
|
"color": "402000",
|
||||||
"collision": true
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,15 +5,15 @@
|
|||||||
"distWeight": 1,
|
"distWeight": 1,
|
||||||
"name": "waste",
|
"name": "waste",
|
||||||
"tilesetAtlas": "world/tilesets/terrain.atlas",
|
"tilesetAtlas": "world/tilesets/terrain.atlas",
|
||||||
"tilesetName": "Waste",
|
"tilesetName": "Colorless",
|
||||||
"terrain": [
|
"terrain": [
|
||||||
{
|
{
|
||||||
"spriteName": "Waste_1",
|
"spriteName": "Colorless_1",
|
||||||
"max": 0.2,
|
"max": 0.2,
|
||||||
"resolution": 5
|
"resolution": 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"spriteName": "Waste_2",
|
"spriteName": "Colorless_2",
|
||||||
"min": 0.8,
|
"min": 0.8,
|
||||||
"max": 1,
|
"max": 1,
|
||||||
"resolution": 5
|
"resolution": 5
|
||||||
@@ -23,9 +23,7 @@
|
|||||||
"height": 0.85,
|
"height": 0.85,
|
||||||
"color": "aeaeae",
|
"color": "aeaeae",
|
||||||
"spriteNames": [
|
"spriteNames": [
|
||||||
"WasteTree",
|
"Stone"
|
||||||
"Stone",
|
|
||||||
"WasteRock"
|
|
||||||
],
|
],
|
||||||
"enemies": [
|
"enemies": [
|
||||||
"Adept Black Wizard",
|
"Adept Black Wizard",
|
||||||
@@ -118,44 +116,94 @@
|
|||||||
"N": 2,
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/colorless_structures.atlas",
|
||||||
"sourcePath": "world/models/waste_structure.png",
|
"sourcePath": "world/structures/models/colorless.png",
|
||||||
"maskPath": "world/masks/circle.png",
|
"maskPath": "world/structures/masks/circle.png",
|
||||||
"periodicInput": false,
|
"height": 0.25,
|
||||||
"height": 0.20000002,
|
"width": 0.25,
|
||||||
"width": 0.20000002,
|
"symmetry": 8,
|
||||||
"symmetry": 4,
|
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "waste_structure",
|
"name": "crater",
|
||||||
"color": "444444",
|
"color": "808080",
|
||||||
"collision": true
|
"collision": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "waste_mountain",
|
"name": "tree",
|
||||||
"color": "9a9a9a",
|
"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
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/colorless_structures.atlas",
|
||||||
"sourcePath": "world/models/hole.png",
|
"sourcePath": "world/structures/models/colorless.png",
|
||||||
"maskPath": "world/masks/ring.png",
|
"maskPath": "world/structures/masks/ring.png",
|
||||||
"height": 0.5,
|
"height": 0.5,
|
||||||
"width": 0.5,
|
"width": 0.5,
|
||||||
"periodicOutput": false,
|
"symmetry": 8,
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "hole",
|
"name": "hole",
|
||||||
"color": "111111",
|
"color": "808080",
|
||||||
"collision": true
|
"collision": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "waste_mountain",
|
"name": "tree",
|
||||||
"color": "9a9a9a",
|
"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
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -23,9 +23,6 @@
|
|||||||
"height": 0.7,
|
"height": 0.7,
|
||||||
"color": "59a650",
|
"color": "59a650",
|
||||||
"spriteNames": [
|
"spriteNames": [
|
||||||
"WoodTree",
|
|
||||||
"WoodTree2",
|
|
||||||
"Bush",
|
|
||||||
"Stump",
|
"Stump",
|
||||||
"Moss",
|
"Moss",
|
||||||
"Stone",
|
"Stone",
|
||||||
@@ -122,39 +119,66 @@
|
|||||||
"N": 2,
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/green_structures.atlas",
|
||||||
"sourcePath": "world/models/forest.png",
|
"sourcePath": "world/structures/models/green.png",
|
||||||
"maskPath": "world/masks/circle.png",
|
"maskPath": "world/structures/masks/circle.png",
|
||||||
"height": 0.20000002,
|
"height": 0.5,
|
||||||
"width": 0.20000002,
|
"width": 0.5,
|
||||||
"symmetry": 1,
|
"symmetry": 1,
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "forest",
|
"name": "water",
|
||||||
"color": "007000",
|
"color": "000080",
|
||||||
"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",
|
|
||||||
"collision": true
|
"collision": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "forest2",
|
"name": "tree",
|
||||||
"color": "009000",
|
"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
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -23,8 +23,7 @@
|
|||||||
"height": 1,
|
"height": 1,
|
||||||
"color": "110903",
|
"color": "110903",
|
||||||
"spriteNames": [
|
"spriteNames": [
|
||||||
"Skull",
|
"Skull"
|
||||||
"PlainsRock"
|
|
||||||
],
|
],
|
||||||
"enemies": [
|
"enemies": [
|
||||||
"Ammit",
|
"Ammit",
|
||||||
@@ -60,9 +59,9 @@
|
|||||||
"N": 2,
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/structures.atlas",
|
||||||
"sourcePath": "world/models/mountain.png",
|
"sourcePath": "world/structures/models/mountain.png",
|
||||||
"maskPath": "world/masks/circle.png",
|
"maskPath": "world/structures/masks/circle.png",
|
||||||
"height": 0.5,
|
"height": 0.5,
|
||||||
"width": 0.5,
|
"width": 0.5,
|
||||||
"symmetry": 8,
|
"symmetry": 8,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
"N": 2,
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/structures.atlas",
|
||||||
"sourcePath": "world/models/fill.png",
|
"sourcePath": "world/models/fill.png",
|
||||||
"maskPath": "world/masks/fill.png",
|
"maskPath": "world/masks/fill.png",
|
||||||
"height": 0.99,
|
"height": 0.99,
|
||||||
|
|||||||
@@ -45,9 +45,9 @@
|
|||||||
"N": 2,
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/structures.atlas",
|
||||||
"sourcePath": "world/models/mountain.png",
|
"sourcePath": "world/structures/models/mountain.png",
|
||||||
"maskPath": "world/masks/circle.png",
|
"maskPath": "world/structures/masks/circle.png",
|
||||||
"height": 0.5,
|
"height": 0.5,
|
||||||
"width": 0.5,
|
"width": 0.5,
|
||||||
"periodicOutput": false,
|
"periodicOutput": false,
|
||||||
|
|||||||
@@ -23,9 +23,6 @@
|
|||||||
"height": 0.7,
|
"height": 0.7,
|
||||||
"color": "b63729",
|
"color": "b63729",
|
||||||
"spriteNames": [
|
"spriteNames": [
|
||||||
"MountainTree",
|
|
||||||
"MountainTree2",
|
|
||||||
"MountainRock",
|
|
||||||
"Gravel"
|
"Gravel"
|
||||||
],
|
],
|
||||||
"enemies": [
|
"enemies": [
|
||||||
@@ -127,21 +124,41 @@
|
|||||||
"N": 2,
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/red_structures.atlas",
|
||||||
"sourcePath": "world/models/mountain.png",
|
"sourcePath": "world/structures/models/red.png",
|
||||||
"maskPath": "world/masks/ring.png",
|
"maskPath": "world/structures/masks/ring.png",
|
||||||
"height": 0.5,
|
"height": 0.5,
|
||||||
"width": 0.5,
|
"width": 0.5,
|
||||||
"periodicOutput": false,
|
"symmetry": 8,
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "mountain",
|
"name": "mountain",
|
||||||
"color": "a07020",
|
"color": "ff0000",
|
||||||
"collision": true
|
"collision": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "mountain_forest",
|
"name": "tree",
|
||||||
"color": "007000",
|
"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
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -149,15 +166,37 @@
|
|||||||
{
|
{
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/red_structures.atlas",
|
||||||
"sourcePath": "world/models/lava.png",
|
"sourcePath": "world/structures/models/volcano.png",
|
||||||
"maskPath": "world/masks/circle.png",
|
"maskPath": "world/structures/masks/circle.png",
|
||||||
"height": 0.2,
|
"height": 0.2,
|
||||||
"width": 0.2,
|
"width": 0.2,
|
||||||
|
"N": 2,
|
||||||
|
"symmetry": 8,
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "lava",
|
"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
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
"height": 0.5,
|
"height": 0.5,
|
||||||
"color": "efe697",
|
"color": "efe697",
|
||||||
"spriteNames": [
|
"spriteNames": [
|
||||||
"PlainsRock",
|
|
||||||
"Skull"
|
"Skull"
|
||||||
],
|
],
|
||||||
"enemies": [
|
"enemies": [
|
||||||
|
|||||||
@@ -23,9 +23,6 @@
|
|||||||
"height": 0.7,
|
"height": 0.7,
|
||||||
"color": "efe697",
|
"color": "efe697",
|
||||||
"spriteNames": [
|
"spriteNames": [
|
||||||
"PlainsTree",
|
|
||||||
"Cactus",
|
|
||||||
"PlainsRock",
|
|
||||||
"DarkGras"
|
"DarkGras"
|
||||||
],
|
],
|
||||||
"enemies": [
|
"enemies": [
|
||||||
@@ -117,33 +114,74 @@
|
|||||||
"N": 2,
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"structureAtlasPath": "world/structures/white_structures.atlas",
|
||||||
"sourcePath": "world/models/plains_forest.png",
|
"sourcePath": "world/structures/models/white.png",
|
||||||
"maskPath": "world/masks/circle.png",
|
"maskPath": "world/structures/masks/circle.png",
|
||||||
"height": 0.20000002,
|
"height": 0.20000002,
|
||||||
"width": 0.20000002,
|
"width": 0.20000002,
|
||||||
"symmetry": 8,
|
"symmetry": 8,
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "plains_forest",
|
"name": "tree",
|
||||||
"color": "9c4000",
|
"color": "ff8000",
|
||||||
|
"collision": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tree2",
|
||||||
|
"color": "008000",
|
||||||
|
"collision": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tree3",
|
||||||
|
"color": "00ff00",
|
||||||
"collision": true
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"N": 2,
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"structureAtlasPath": "world/tilesets/structures.atlas",
|
"symmetry": 8,
|
||||||
"sourcePath": "world/models/plateau.png",
|
"structureAtlasPath": "world/structures/white_structures.atlas",
|
||||||
"maskPath": "world/masks/ring.png",
|
"sourcePath": "world/structures/models/desert.png",
|
||||||
|
"maskPath": "world/structures/masks/ring.png",
|
||||||
"height": 0.5,
|
"height": 0.5,
|
||||||
"width": 0.5,
|
"width": 0.5,
|
||||||
"periodicOutput": false,
|
|
||||||
"mappingInfo": [
|
"mappingInfo": [
|
||||||
{
|
{
|
||||||
"name": "plateau",
|
"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
|
"collision": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -6369,9 +6369,7 @@
|
|||||||
"IdentityBlack",
|
"IdentityBlack",
|
||||||
"IdentityGreen",
|
"IdentityGreen",
|
||||||
"IdentityAbzan",
|
"IdentityAbzan",
|
||||||
"BiomeColorless",
|
"BiomeBlue"
|
||||||
"BiomeWhite",
|
|
||||||
"BiomeBlack"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -7242,7 +7240,7 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"colors": "W",
|
"colors": "GW",
|
||||||
"questTags": [
|
"questTags": [
|
||||||
"Elephant",
|
"Elephant",
|
||||||
"Beast",
|
"Beast",
|
||||||
@@ -12544,7 +12542,7 @@
|
|||||||
"spawnRate": 1,
|
"spawnRate": 1,
|
||||||
"difficulty": 0.1,
|
"difficulty": 0.1,
|
||||||
"speed": 25,
|
"speed": 25,
|
||||||
"scale": 0.6,
|
"scale": 1.3,
|
||||||
"life": 11,
|
"life": 11,
|
||||||
"rewards": [
|
"rewards": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,36 +21,12 @@ Reed
|
|||||||
Reed
|
Reed
|
||||||
xy: 80, 0
|
xy: 80, 0
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Reed
|
|
||||||
xy: 64, 16
|
|
||||||
size: 16, 16
|
|
||||||
Reed
|
|
||||||
xy: 80, 16
|
|
||||||
size: 16, 16
|
|
||||||
DarkWood
|
DarkWood
|
||||||
xy: 96, 0
|
xy: 96, 0
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
DarkWood
|
DarkWood
|
||||||
xy: 112, 0
|
xy: 112, 0
|
||||||
size: 16, 16
|
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
|
|
||||||
DarkWood
|
DarkWood
|
||||||
xy: 0, 16
|
xy: 0, 16
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
@@ -63,36 +39,60 @@ DarkWood
|
|||||||
DarkWood
|
DarkWood
|
||||||
xy: 48, 16
|
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
|
DarkGras
|
||||||
xy: 0, 32
|
xy: 0, 32
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
DarkGras
|
DarkGras
|
||||||
xy: 16, 32
|
xy: 16, 32
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
DarkGras
|
|
||||||
xy: 0, 48
|
|
||||||
size: 16, 16
|
|
||||||
DarkGras
|
|
||||||
xy: 16, 48
|
|
||||||
size: 16, 16
|
|
||||||
Stone
|
Stone
|
||||||
xy: 32, 32
|
xy: 32, 32
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Stone
|
Stone
|
||||||
xy: 48, 32
|
xy: 48, 32
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Stone
|
|
||||||
xy: 32, 48
|
|
||||||
size: 16, 16
|
|
||||||
Stone
|
|
||||||
xy: 48, 48
|
|
||||||
size: 16, 16
|
|
||||||
Gravel
|
Gravel
|
||||||
xy: 64, 32
|
xy: 64, 32
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Gravel
|
Gravel
|
||||||
xy: 80, 32
|
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
|
Gravel
|
||||||
xy: 64, 48
|
xy: 64, 48
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
@@ -105,42 +105,42 @@ Flower
|
|||||||
Flower
|
Flower
|
||||||
xy: 16, 64
|
xy: 16, 64
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Flower
|
|
||||||
xy: 0, 80
|
|
||||||
size: 16, 16
|
|
||||||
Flower
|
|
||||||
xy: 16, 80
|
|
||||||
size: 16, 16
|
|
||||||
Stone
|
Stone
|
||||||
xy: 32, 64
|
xy: 32, 64
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Stone
|
Stone
|
||||||
xy: 48, 64
|
xy: 48, 64
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
|
Moss
|
||||||
|
xy: 64, 64
|
||||||
|
size: 16, 16
|
||||||
|
Moss
|
||||||
|
xy: 80, 64
|
||||||
|
size: 16, 16
|
||||||
|
Wood
|
||||||
|
xy: 96, 64
|
||||||
|
size: 16, 16
|
||||||
|
Wood
|
||||||
|
xy: 112, 64
|
||||||
|
size: 16, 16
|
||||||
|
Flower
|
||||||
|
xy: 0, 80
|
||||||
|
size: 16, 16
|
||||||
|
Flower
|
||||||
|
xy: 16, 80
|
||||||
|
size: 16, 16
|
||||||
Stone
|
Stone
|
||||||
xy: 32, 80
|
xy: 32, 80
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Stone
|
Stone
|
||||||
xy: 48, 80
|
xy: 48, 80
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Moss
|
|
||||||
xy: 64, 64
|
|
||||||
size: 16, 16
|
|
||||||
Moss
|
|
||||||
xy: 80, 64
|
|
||||||
size: 16, 16
|
|
||||||
Moss
|
Moss
|
||||||
xy: 64, 80
|
xy: 64, 80
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Moss
|
Moss
|
||||||
xy: 80, 80
|
xy: 80, 80
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Wood
|
|
||||||
xy: 96, 64
|
|
||||||
size: 16, 16
|
|
||||||
Wood
|
|
||||||
xy: 112, 64
|
|
||||||
size: 16, 16
|
|
||||||
Wood
|
Wood
|
||||||
xy: 96, 80
|
xy: 96, 80
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
@@ -162,6 +162,15 @@ WasteRock
|
|||||||
WasteRock
|
WasteRock
|
||||||
xy: 64, 96
|
xy: 64, 96
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
|
Placeholder
|
||||||
|
xy: 80, 96
|
||||||
|
size: 16,16
|
||||||
|
SwampTree2
|
||||||
|
xy: 96, 96
|
||||||
|
size: 16, 16
|
||||||
|
SwampTree2
|
||||||
|
xy: 112, 96
|
||||||
|
size: 16, 16
|
||||||
SwampTree
|
SwampTree
|
||||||
xy: 0, 112
|
xy: 0, 112
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
@@ -174,12 +183,6 @@ SwampTree
|
|||||||
Skull
|
Skull
|
||||||
xy: 48, 112
|
xy: 48, 112
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
Skull
|
|
||||||
xy: 112, 144
|
|
||||||
size: 16, 16
|
|
||||||
Skull
|
|
||||||
xy: 112, 128
|
|
||||||
size: 16, 16
|
|
||||||
SwampRock
|
SwampRock
|
||||||
xy: 64, 112
|
xy: 64, 112
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
@@ -192,12 +195,6 @@ SwampTree2
|
|||||||
SwampTree2
|
SwampTree2
|
||||||
xy: 112, 112
|
xy: 112, 112
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
SwampTree2
|
|
||||||
xy: 96, 96
|
|
||||||
size: 16, 16
|
|
||||||
SwampTree2
|
|
||||||
xy: 112, 96
|
|
||||||
size: 16, 16
|
|
||||||
PlainsTree
|
PlainsTree
|
||||||
xy: 0, 128
|
xy: 0, 128
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
@@ -214,11 +211,14 @@ Cactus
|
|||||||
xy: 64, 128
|
xy: 64, 128
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
PlainsRock
|
PlainsRock
|
||||||
xy: 70, 128
|
xy: 80, 128
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
PlainsRock
|
PlainsRock
|
||||||
xy: 96, 128
|
xy: 96, 128
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
|
Skull
|
||||||
|
xy: 112, 128
|
||||||
|
size: 16, 16
|
||||||
IslandTree
|
IslandTree
|
||||||
xy: 0, 144
|
xy: 0, 144
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
@@ -234,6 +234,15 @@ Shell
|
|||||||
Shell
|
Shell
|
||||||
xy: 64, 144
|
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
|
WoodTree
|
||||||
xy: 0, 160
|
xy: 0, 160
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
@@ -270,24 +279,108 @@ MountainTree2
|
|||||||
MountainTree2
|
MountainTree2
|
||||||
xy: 48, 176
|
xy: 48, 176
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
MountainTree2
|
|
||||||
xy: 96, 176
|
|
||||||
size: 16, 16
|
|
||||||
MountainTree2
|
|
||||||
xy: 112, 176
|
|
||||||
size: 16, 16
|
|
||||||
MountainRock
|
MountainRock
|
||||||
xy: 64, 176
|
xy: 64, 176
|
||||||
size: 16, 16
|
size: 16, 16
|
||||||
MountainRock
|
MountainRock
|
||||||
xy: 80, 176
|
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
|
LargeMountainRock
|
||||||
xy: 96, 224
|
xy: 96, 224
|
||||||
size: 32, 32
|
size: 32, 32
|
||||||
LargePlainsRock
|
LargePlainsRock
|
||||||
xy: 96, 256
|
xy: 96, 256
|
||||||
size: 32, 32
|
size: 32, 32
|
||||||
|
Placeholder
|
||||||
|
xy: 0, 256
|
||||||
|
size: 16, 16
|
||||||
|
WasteRock
|
||||||
|
xy: 16, 256
|
||||||
|
size: 16, 16
|
||||||
LargeSwampRock
|
LargeSwampRock
|
||||||
xy: 32, 256
|
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
|
||||||
@@ -79,21 +79,21 @@
|
|||||||
"name":"WasteTree",
|
"name":"WasteTree",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"endArea":0.2,
|
"endArea":0.2,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :10,
|
"resolution" :10,
|
||||||
"density":0.7
|
"density":0.7
|
||||||
},{
|
},{
|
||||||
"name":"WasteRock",
|
"name":"WasteRock",
|
||||||
"startArea":0.8,
|
"startArea":0.8,
|
||||||
"endArea":1.0,
|
"endArea":1.0,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :10,
|
"resolution" :10,
|
||||||
"density":0.5
|
"density":0.5
|
||||||
},{
|
},{
|
||||||
"name":"SwampTree",
|
"name":"SwampTree",
|
||||||
"startArea":0.8,
|
"startArea":0.8,
|
||||||
"endArea":1.0,
|
"endArea":1.0,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :10,
|
"resolution" :10,
|
||||||
"density":0.5
|
"density":0.5
|
||||||
},{
|
},{
|
||||||
@@ -106,45 +106,45 @@
|
|||||||
"name":"SwampRock",
|
"name":"SwampRock",
|
||||||
"startArea":0.5,
|
"startArea":0.5,
|
||||||
"endArea":0.6,
|
"endArea":0.6,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"density":0.1
|
"density":0.1
|
||||||
},{
|
},{
|
||||||
"name":"SwampTree2",
|
"name":"SwampTree2",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"endArea":0.2,
|
"endArea":0.2,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :10,
|
"resolution" :10,
|
||||||
"density":0.7
|
"density":0.7
|
||||||
},{
|
},{
|
||||||
"name":"PlainsTree",
|
"name":"PlainsTree",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"endArea":0.2,
|
"endArea":0.2,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :10,
|
"resolution" :10,
|
||||||
"density":0.7
|
"density":0.7
|
||||||
},{
|
},{
|
||||||
"name":"Cactus",
|
"name":"Cactus",
|
||||||
"startArea":0.5,
|
"startArea":0.5,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"endArea":0.7,
|
"endArea":0.7,
|
||||||
"density":0.06
|
"density":0.06
|
||||||
},{
|
},{
|
||||||
"name":"PlainsRock",
|
"name":"PlainsRock",
|
||||||
"startArea":0.7,
|
"startArea":0.7,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"endArea":0.99,
|
"endArea":0.99,
|
||||||
"density":0.06
|
"density":0.06
|
||||||
},{
|
},{
|
||||||
"name":"IslandTree",
|
"name":"IslandTree",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"endArea":0.2,
|
"endArea":0.2,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :10,
|
"resolution" :10,
|
||||||
"density":0.7
|
"density":0.7
|
||||||
},{
|
},{
|
||||||
"name":"Coral",
|
"name":"Coral",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"endArea":0.9,
|
"endArea":0.9,
|
||||||
"density":0.01
|
"density":0.01
|
||||||
},{
|
},{
|
||||||
@@ -157,65 +157,65 @@
|
|||||||
"name":"WoodTree",
|
"name":"WoodTree",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"endArea":0.2,
|
"endArea":0.2,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :10,
|
"resolution" :10,
|
||||||
"density":0.7
|
"density":0.7
|
||||||
},{
|
},{
|
||||||
"name":"WoodTree2",
|
"name":"WoodTree2",
|
||||||
"startArea":0.8,
|
"startArea":0.8,
|
||||||
"endArea":0.99,
|
"endArea":0.99,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :5,
|
"resolution" :5,
|
||||||
"density":0.7
|
"density":0.7
|
||||||
},{
|
},{
|
||||||
"name":"Bush",
|
"name":"Bush",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"endArea":0.2,
|
"endArea":0.2,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :5,
|
"resolution" :5,
|
||||||
"density":0.4
|
"density":0.4
|
||||||
},{
|
},{
|
||||||
"name":"Stump",
|
"name":"Stump",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"layer":0,
|
"layer":-1,
|
||||||
"endArea":0.9,
|
"endArea":0.9,
|
||||||
"density":0.01
|
"density":0.01
|
||||||
},{
|
},{
|
||||||
"name":"MountainTree",
|
"name":"MountainTree",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"endArea":0.2,
|
"endArea":0.2,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :5,
|
"resolution" :5,
|
||||||
"density":0.7
|
"density":0.7
|
||||||
},{
|
},{
|
||||||
"name":"MountainTree2",
|
"name":"MountainTree2",
|
||||||
"startArea":0.8,
|
"startArea":0.8,
|
||||||
"endArea":0.99,
|
"endArea":0.99,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"resolution" :5,
|
"resolution" :5,
|
||||||
"density":0.7
|
"density":0.7
|
||||||
},{
|
},{
|
||||||
"name":"MountainRock",
|
"name":"MountainRock",
|
||||||
"startArea":0.1,
|
"startArea":0.1,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"endArea":0.9,
|
"endArea":0.9,
|
||||||
"density":0.08
|
"density":0.08
|
||||||
},{
|
},{
|
||||||
"name":"LargeMountainRock",
|
"name":"LargeMountainRock",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"endArea":0.9,
|
"endArea":0.9,
|
||||||
"density":0.02
|
"density":0.02
|
||||||
},{
|
},{
|
||||||
"name":"LargePlainsRock",
|
"name":"LargePlainsRock",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"endArea":0.9,
|
"endArea":0.9,
|
||||||
"density":0.01
|
"density":0.01
|
||||||
},{
|
},{
|
||||||
"name":"LargeSwampRock",
|
"name":"LargeSwampRock",
|
||||||
"startArea":0.0,
|
"startArea":0.0,
|
||||||
"layer":0,
|
"layer":1,
|
||||||
"endArea":0.9,
|
"endArea":0.9,
|
||||||
"density":0.01
|
"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 |
@@ -0,0 +1,32 @@
|
|||||||
|
red_structures.png
|
||||||
|
size: 144,192
|
||||||
|
format: RGBA8888
|
||||||
|
filter: Nearest,Nearest
|
||||||
|
repeat: none
|
||||||
|
lava
|
||||||
|
xy: 0, 0
|
||||||
|
size: 48, 64
|
||||||
|
tree
|
||||||
|
xy: 48,0
|
||||||
|
size:48,64
|
||||||
|
tree2
|
||||||
|
xy: 96,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
|
||||||
|
rock
|
||||||
|
xy: 0, 128
|
||||||
|
size: 48, 64
|
||||||
|
mountain
|
||||||
|
xy: 48, 128
|
||||||
|
size: 48,64
|
||||||
|
tree4
|
||||||
|
xy: 96,128
|
||||||
|
size: 48,64
|
||||||