-
Notifications
You must be signed in to change notification settings - Fork 46
Expand file tree
/
Copy pathModifyDamageSpell.java
More file actions
174 lines (165 loc) · 4.76 KB
/
ModifyDamageSpell.java
File metadata and controls
174 lines (165 loc) · 4.76 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
173
174
package net.demilich.metastone.game.spells;
import net.demilich.metastone.game.GameContext;
import net.demilich.metastone.game.Player;
import net.demilich.metastone.game.entities.Entity;
import net.demilich.metastone.game.spells.desc.SpellArg;
import net.demilich.metastone.game.spells.desc.SpellDesc;
import net.demilich.metastone.game.spells.desc.valueprovider.AlgebraicOperation;
import net.demilich.metastone.game.targeting.EntityReference;
import net.demilich.metastone.game.cards.Attribute;
/**
* Modifies the amount of damage that is currently about to be dealt.
* <p>
* The expression for the modification is {@code DAMAGE OPERATION VALUE}. In other words, if {@link SpellArg#OPERATION}
* is {@link AlgebraicOperation#ADD}, the damage is 2 and the value is 4, the new damage will be {@code 2 + 4 = 6}.
* <p>
* Several triggers cast their spells at the right moment to modify damage. For <b>example</b>, a common trigger is a
* {@link net.demilich.metastone.game.spells.trigger.PreDamageTrigger}, for text like "Your minions can only take 1
* damage at a time":
* <pre>
* {
* "eventTrigger": {
* "class": "PreDamageTrigger",
* "fireCondition": {
* "class": "OwnedByPlayerCondition",
* "targetPlayer": "SELF"
* },
* "targetEntityType": "MINION",
* "targetPlayer": "SELF"
* },
* "spell": {
* "class": "ModifyDamageSpell",
* "value": 1,
* "operation": "SET"
* }
* }
* </pre>
* Or, for <b>example</b>, the {@link net.demilich.metastone.game.spells.trigger.FatalDamageTrigger} is useful for text
* like "When your hero takes fatal damage, heal for the amount instead.":
* <pre>
* {
* "eventTrigger": {
* "class": "FatalDamageTrigger",
* "sourcePlayer": "BOTH",
* "targetEntityType": "HERO",
* "targetPlayer": "SELF"
* },
* "spell": {
* "class": "MetaSpell",
* "spells": [
* {
* "class": "ModifyDamageSpell",
* "value": 0,
* "operation": "SET"
* },
* {
* "class": "HealSpell",
* "target": "FRIENDLY_HERO",
* "value": {
* "class": "EventValueProvider"
* }
* }
* ]
* }
* }
* </pre>
* Finally, to <b>double</b> damage dealt by this minion to heroes:
* <pre>
* {
* "eventTrigger": {
* "class": "PreDamageTrigger",
* "hostTargetType": "IGNORE_OTHER_SOURCES",
* "targetEntityType": "HERO"
* },
* "spell": {
* "class": "ModifyDamageSpell",
* "value": 2,
* "operation": "MULTIPLY"
* }
* }
* </pre>
*/
public class ModifyDamageSpell extends Spell {
public static SpellDesc create(int value, AlgebraicOperation operation) {
SpellDesc desc = new SpellDesc(ModifyDamageSpell.class);
desc.put(SpellArg.VALUE, value);
desc.put(SpellArg.OPERATION, operation);
return desc;
}
@Override
protected void onCast(GameContext context, Player player, SpellDesc desc, Entity source, Entity target) {
if (context.getDamageStack().isEmpty()) {
return;
}
int damage = context.getDamageStack().pop();
AlgebraicOperation operation = (AlgebraicOperation) desc.get(SpellArg.OPERATION);
int value = desc.getValue(SpellArg.VALUE, context, player, target, source, 0);
int minDamage = 0;
// Fel's grip will modify all incoming damage when played as a spell.
EntityReference eventTarget = context.getEventTargetStack().peek();
boolean hasTakeDoubleDamage = false;
if (eventTarget != null) {
Entity damageTarget = context.resolveSingleTarget(eventTarget);
hasTakeDoubleDamage = damageTarget.hasAttribute(Attribute.TAKE_DOUBLE_DAMAGE) || damageTarget.hasAttribute(Attribute.AURA_TAKE_DOUBLE_DAMAGE);
}
switch (operation) {
case ADD:
if (hasTakeDoubleDamage) {
value *= 2;
}
damage += value;
break;
case SUBTRACT:
if (hasTakeDoubleDamage) {
value *= 2;
}
damage -= value;
damage = Math.max(minDamage, damage);
break;
case MODULO:
if (hasTakeDoubleDamage) {
damage /= 2;
}
damage %= value;
if (hasTakeDoubleDamage) {
damage *= 2;
}
break;
case MULTIPLY:
damage *= value;
break;
case DIVIDE:
damage /= value;
damage = Math.max(minDamage, damage);
break;
case NEGATE:
damage = -damage;
break;
case SET:
if (hasTakeDoubleDamage) {
value *= 2;
}
damage = value;
break;
case MINIMUM:
if (hasTakeDoubleDamage) {
value *= 2;
}
if (damage < value) {
damage = value;
}
break;
case MAXIMUM:
if (hasTakeDoubleDamage) {
value *= 2;
}
if (damage > value) {
damage = value;
}
break;
default:
break;
}
context.getDamageStack().push(damage);
}
}