-
Notifications
You must be signed in to change notification settings - Fork 46
Expand file tree
/
Copy pathDamageSpell.java
More file actions
173 lines (159 loc) · 6.22 KB
/
DamageSpell.java
File metadata and controls
173 lines (159 loc) · 6.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package net.demilich.metastone.game.spells;
import com.hiddenswitch.spellsource.rpc.Spellsource.DamageTypeMessage.DamageType;
import net.demilich.metastone.game.GameContext;
import net.demilich.metastone.game.Player;
import net.demilich.metastone.game.cards.Attribute;
import net.demilich.metastone.game.entities.Actor;
import net.demilich.metastone.game.entities.Entity;
import net.demilich.metastone.game.logic.GameLogic;
import net.demilich.metastone.game.spells.desc.SpellArg;
import net.demilich.metastone.game.spells.desc.SpellDesc;
import net.demilich.metastone.game.targeting.EntityReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
/**
* Deals {@link SpellArg#VALUE} damage to the specified {@code target}.
* <p>
* When {@link SpellArg#IGNORE_SPELL_DAMAGE} is set to {@code true}, ignores {@link Attribute#SPELL_DAMAGE} bonuses. By
* default, spell damage dealt anything other than a spell card cannot deal spell damage.
* <p>
* The amount of damage dealt can be modified by other, prior effects using {@link ModifyDamageSpell}. This is typically
* done during the {@link net.demilich.metastone.game.spells.trigger.PreDamageTrigger}'s {@link
* net.demilich.metastone.game.events.PreDamageEvent}.
* <p>
* For example, "Battlecry: Deal 6 damage to all other characters:"
* <pre>
* "battlecry": {
* "targetSelection": "NONE",
* "spell": {
* "class": "DamageSpell",
* "target": "ALL_OTHER_CHARACTERS",
* "value": 6
* }
* }
* </pre>
* A significantly more complicated example, "Deal 10 damage to a minion and excess damage to adjacent ones."
* <pre>
* "spell": {
* "class": "MetaSpell",
* "value": {
* "class": "AttributeValueProvider",
* "attribute": "HP"
* },
* "spells": [
* {
* "class": "AdjacentEffectSpell",
* "spell1": {
* "class": "DamageSpell",
* "value": {
* "class": "AlgebraicValueProvider",
* "operation": "MAXIMUM",
* "value1": 0,
* "value2": {
* "class": "AlgebraicValueProvider",
* "operation": "MINIMUM",
* "value1": 10,
* "value2": {
* "class": "GameValueProvider",
* "gameValue": "SPELL_VALUE"
* }
* }
* }
* },
* "spell2": {
* "class": "DamageSpell",
* "value": {
* "class": "AlgebraicValueProvider",
* "operation": "MINIMUM",
* "value1": 10,
* "value2": {
* "class": "AlgebraicValueProvider",
* "operation": "MAXIMUM",
* "value1": {
* "class": "AlgebraicValueProvider",
* "operation": "SUBTRACT",
* "value1": 10,
* "value2": {
* "class": "GameValueProvider",
* "gameValue": "SPELL_VALUE"
* }
* },
* "value2": 0
* }
* }
* }
* }
* ]
* }
* </pre>
* Observe the way arithmetic is performed inside the {@code "value"} fields of the {@link DamageSpell}.
*
* @see ModifyDamageSpell to modify damage from physical attacks, the {@link MissilesSpell} and this spell.
* @see HealSpell to heal. Don't use negative values.
* @see MissilesSpell to fire random missiles that calculate spell damage correctly.
*/
public class DamageSpell extends Spell {
private static Logger logger = LoggerFactory.getLogger(DamageSpell.class);
public static SpellDesc create(EntityReference target, int damage) {
return create(target, damage, false);
}
public static SpellDesc create(EntityReference target, int damage, boolean randomTarget) {
return create(target, damage, null, randomTarget);
}
public static SpellDesc create(EntityReference target, int damage, Predicate<Entity> targetFilter, boolean randomTarget) {
Map<SpellArg, Object> arguments = new SpellDesc(DamageSpell.class);
arguments.put(SpellArg.VALUE, damage);
arguments.put(SpellArg.TARGET, target);
arguments.put(SpellArg.RANDOM_TARGET, randomTarget);
if (targetFilter != null) {
arguments.put(SpellArg.FILTER, targetFilter);
}
return new SpellDesc(arguments);
}
public static SpellDesc create(int damage) {
return create(null, damage);
}
public static SpellDesc create() {
return new SpellDesc(DamageSpell.class);
}
@Override
public void cast(GameContext context, Player player, SpellDesc desc, Entity source, List<Entity> targets) {
// For now, ALL damage spell effects will emit a missile
GameLogic.fireMissileEvent(context, player, source, targets, getDamageType(context, player, source));
super.cast(context, player, desc, source, targets);
}
@Override
protected void onCast(GameContext context, Player player, SpellDesc desc, Entity source, Entity target) {
checkArguments(logger, context, source, desc, SpellArg.IGNORE_SPELL_DAMAGE, SpellArg.VALUE);
if (!(target instanceof Actor)) {
logger.error("onCast {} {}: Cannot deal damage to non-Actor target {}", context.getGameId(), source, target);
return;
}
int damage = getDamage(context, player, desc, source, target);
boolean ignoreSpellDamage = desc.getBool(SpellArg.IGNORE_SPELL_DAMAGE);
if (damage < 0) {
logger.error("onCast {} {}: Suspicious negative damage call", context.getGameId(), source);
}
context.getLogic().damage(player, (Actor) target, damage, source, ignoreSpellDamage, getDamageType(context, player, source));
}
public static int getDamage(GameContext context, Player player, SpellDesc desc, Entity source, Entity target) {
int damage = 0;
// TODO Rewrite to more accurate way to grab Damage Stack damage.
if (!desc.containsKey(SpellArg.VALUE) && !context.getDamageStack().isEmpty()) {
Integer peek = context.getDamageStack().peek();
if (peek != null) {
damage = peek;
}
} else {
damage = desc.getValue(SpellArg.VALUE, context, player, target, source, 0);
}
return damage;
}
protected EnumSet<DamageType> getDamageType(GameContext context, Player player, Entity source) {
return EnumSet.of(DamageType.MAGICAL);
}
}