Skip to content

Commit b725c19

Browse files
committed
Add support for devices
* Add support for using devices (and tested) * Also added Tattle since with othersClank support it was simple. * Re-ordered CardType definitions to have cost last. I attempted to add a compile time assert for set == CardSet.starter || (skillCost > 0 || swordsCost >0), but ran into dart-lang/language#312
1 parent 3134c06 commit b725c19

File tree

5 files changed

+103
-25
lines changed

5 files changed

+103
-25
lines changed

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ dart run bin/simulate.dart
1313
## Missing Features
1414
* Crystal Cave exhaustion
1515
* Many Cards
16-
* Devices
17-
* Combat
1816
* Market
1917
* Healing
2018
* Various card effects (trashing, teleport, etc.)
2119
* Missing "deep" half of map.
20+
* Spending health for swords to move.
2221

2322
## Issues
24-
* Random planners take 100s of turns to complete game.
23+
* Most games end w/o escape since random planning just walks around.

lib/cards.dart

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -128,57 +128,57 @@ const List<CardType> baseSetAllCardTypes = [
128128
set: CardSet.dungeon,
129129
count: 3,
130130
points: 4,
131-
skillCost: 4,
132131
drawCards: 1,
133132
dragon: true,
134133
acquireClank: 2,
134+
skillCost: 4,
135135
),
136136
CardType(
137137
name: 'Ruby',
138138
set: CardSet.dungeon,
139139
count: 2,
140140
points: 6,
141-
skillCost: 6,
142141
drawCards: 1,
143142
dragon: true,
144143
acquireClank: 2,
144+
skillCost: 6,
145145
),
146146
CardType(
147147
name: 'Emerald',
148148
set: CardSet.dungeon,
149149
count: 2,
150150
points: 5,
151-
skillCost: 5,
152151
drawCards: 1,
153152
dragon: true,
154153
acquireClank: 2,
154+
skillCost: 5,
155155
),
156156
CardType(
157157
name: 'Bracers of Agility',
158158
set: CardSet.dungeon,
159159
points: 2,
160160
count: 2,
161-
skillCost: 5,
162161
drawCards: 2,
162+
skillCost: 5,
163163
),
164164
CardType(
165165
name: 'Pickaxe',
166166
set: CardSet.dungeon,
167167
count: 2,
168168
points: 2,
169169
swords: 2,
170-
skillCost: 4,
171170
gainGold: 2,
171+
skillCost: 4,
172172
),
173173
CardType(
174174
name: 'Lucky Coin',
175175
set: CardSet.dungeon,
176176
count: 2,
177177
points: 1,
178178
skill: 1,
179-
skillCost: 1,
180179
clank: 1,
181180
drawCards: 1,
181+
skillCost: 1,
182182
),
183183
CardType(
184184
name: 'Tunnel Guide',
@@ -187,8 +187,8 @@ const List<CardType> baseSetAllCardTypes = [
187187
points: 1,
188188
swords: 1,
189189
boots: 1,
190-
skillCost: 1,
191190
companion: true,
191+
skillCost: 1,
192192
),
193193
CardType(
194194
name: 'Move Silently',
@@ -204,8 +204,8 @@ const List<CardType> baseSetAllCardTypes = [
204204
count: 2,
205205
points: 2,
206206
swords: 3,
207-
skillCost: 3,
208207
acquireSwords: 1,
208+
skillCost: 3,
209209
),
210210
CardType(
211211
name: 'Sneak',
@@ -227,6 +227,14 @@ const List<CardType> baseSetAllCardTypes = [
227227
acquireHearts: 1,
228228
skillCost: 3,
229229
),
230+
CardType(
231+
name: 'Tattle',
232+
set: CardSet.dungeon,
233+
count: 2,
234+
skill: 2,
235+
othersClank: 1,
236+
skillCost: 3,
237+
),
230238

231239
// Unique Cards
232240
CardType(
@@ -269,18 +277,18 @@ const List<CardType> baseSetAllCardTypes = [
269277
clank: 3,
270278
drawCards: 3,
271279
points: 1,
272-
skillCost: 5,
273280
companion: true,
274281
dragon: true,
282+
skillCost: 5,
275283
),
276284
CardType(
277285
name: 'Scepter of the Ape Lord',
278286
set: CardSet.dungeon,
279287
count: 1,
280288
clank: 3,
281289
skill: 3,
282-
skillCost: 3,
283290
points: 3,
291+
skillCost: 3,
284292
),
285293
CardType(
286294
name: 'Singing Sword',
@@ -290,8 +298,8 @@ const List<CardType> baseSetAllCardTypes = [
290298
skill: 3,
291299
swords: 2,
292300
clank: 1,
293-
skillCost: 5,
294301
dragon: true,
302+
skillCost: 5,
295303
),
296304
CardType(
297305
name: 'Elven Cloak',
@@ -337,78 +345,78 @@ const List<CardType> baseSetAllCardTypes = [
337345
name: 'Goblin',
338346
set: CardSet.reserve,
339347
count: 1,
340-
swordsCost: 2,
341348
gainGold: 1,
342349
neverDiscards: true,
350+
swordsCost: 2,
343351
),
344352
CardType(
345353
name: 'Cave Troll',
346354
set: CardSet.dungeon,
347355
count: 1,
348356
location: Location.deep,
349357
dragon: true,
350-
swordsCost: 4,
351358
gainGold: 3,
352359
drawCards: 2,
360+
swordsCost: 4,
353361
),
354362
CardType(
355363
name: 'Belcher',
356364
set: CardSet.dungeon,
357365
count: 2,
358366
dragon: true,
359-
swordsCost: 2,
360367
gainGold: 4,
361368
clank: 2,
369+
swordsCost: 2,
362370
),
363371
CardType(
364372
name: 'Animated Door',
365373
set: CardSet.dungeon,
366374
count: 2,
367375
dragon: true,
368-
swordsCost: 1,
369376
boots: 1,
377+
swordsCost: 1,
370378
),
371379
CardType(
372380
name: 'Ogre',
373381
set: CardSet.dungeon,
374382
count: 2,
375383
dragon: true,
376-
swordsCost: 3,
377384
gainGold: 5,
385+
swordsCost: 3,
378386
),
379387
CardType(
380388
name: 'Orc Grunt',
381389
set: CardSet.dungeon,
382390
count: 3,
383391
dragon: true,
384-
swordsCost: 2,
385392
gainGold: 3,
393+
swordsCost: 2,
386394
),
387395
CardType(
388396
name: 'Crystal Golem',
389397
set: CardSet.dungeon,
390398
count: 2,
391399
location: Location.crystalCave,
392-
swordsCost: 3,
393400
skill: 3,
401+
swordsCost: 3,
394402
),
395403
CardType(
396404
name: 'Kobold',
397405
set: CardSet.dungeon,
398406
count: 3,
399407
dragon: true,
400408
danger: true,
401-
swordsCost: 1,
402409
skill: 1,
410+
swordsCost: 1,
403411
),
404412
CardType(
405413
name: 'Watcher',
406414
set: CardSet.dungeon,
407415
count: 3,
408416
arriveClank: 1,
409-
swordsCost: 3,
410417
gainGold: 3,
411418
othersClank: 1,
419+
swordsCost: 3,
412420
),
413421
CardType(
414422
name: 'Overlord',
@@ -418,4 +426,25 @@ const List<CardType> baseSetAllCardTypes = [
418426
swordsCost: 2,
419427
drawCards: 2,
420428
),
429+
430+
// Devices
431+
CardType(
432+
name: 'Ladder',
433+
set: CardSet.dungeon,
434+
isDevice: true,
435+
count: 2,
436+
boots: 2,
437+
skillCost: 3,
438+
),
439+
CardType(
440+
name: 'The Vault',
441+
set: CardSet.dungeon,
442+
location: Location.deep,
443+
isDevice: true,
444+
count: 1,
445+
dragon: true,
446+
gainGold: 5,
447+
clank: 3,
448+
skillCost: 3,
449+
),
421450
];

lib/clank.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class ClankGame {
140140

141141
void executePurchase(Turn turn, Purchase action) {
142142
CardType cardType = action.cardType;
143+
assert(cardType.interaction == Interaction.buy);
143144
turn.skill -= cardType.skillCost;
144145
assert(turn.skill >= 0);
145146
assert(cardType.swordsCost == 0);
@@ -152,6 +153,7 @@ class ClankGame {
152153

153154
void executeFight(Turn turn, Fight action) {
154155
CardType cardType = action.cardType;
156+
assert(cardType.interaction == Interaction.fight);
155157
turn.swords -= cardType.swordsCost;
156158
assert(turn.swords >= 0);
157159
assert(cardType.skillCost == 0);
@@ -189,6 +191,19 @@ class ClankGame {
189191
turn.player.gold += cardType.gainGold;
190192
}
191193

194+
void executeUseDevice(Turn turn, UseDevice action) {
195+
CardType cardType = action.cardType;
196+
assert(cardType.interaction == Interaction.use);
197+
turn.skill -= cardType.skillCost;
198+
assert(turn.skill >= 0);
199+
assert(cardType.swordsCost == 0);
200+
201+
Card card = board.takeCard(cardType);
202+
board.dungeonDiscard.add(card);
203+
executeCardUseEffects(turn, action.cardType);
204+
print('${turn.player} used $card');
205+
}
206+
192207
void executeAction(Turn turn, Action action) {
193208
if (action is PlayCard) {
194209
turn.player.deck.playCard(action.cardType);
@@ -210,6 +225,10 @@ class ClankGame {
210225
executeFight(turn, action);
211226
return;
212227
}
228+
if (action is UseDevice) {
229+
executeUseDevice(turn, action);
230+
return;
231+
}
213232
assert(false);
214233
}
215234

lib/planner.dart

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ class Fight extends Action {
5050
}
5151
}
5252

53+
class UseDevice extends Action {
54+
final CardType cardType;
55+
UseDevice({required this.cardType}) {
56+
assert(cardType.skillCost > 0);
57+
assert(cardType.swordsCost == 0);
58+
}
59+
}
60+
5361
class EndTurn extends Action {}
5462

5563
// Planner can't modify turn directly?
@@ -176,7 +184,7 @@ class RandomPlanner implements Planner {
176184
}
177185

178186
Iterable<Action> possiblePurchases(Turn turn, Board board) sync* {
179-
bool canAfford(CardType cardType) {
187+
bool canAffordPurchase(CardType cardType) {
180188
if (cardType.interaction != Interaction.buy) return false;
181189
if (cardType.skillCost > turn.skill) return false;
182190
return true;
@@ -188,16 +196,25 @@ class RandomPlanner implements Planner {
188196
return true;
189197
}
190198

199+
bool canAffordDevice(CardType cardType) {
200+
if (cardType.interaction != Interaction.use) return false;
201+
if (cardType.skillCost > turn.skill) return false;
202+
return true;
203+
}
204+
191205
for (var cardType in board.availableCardTypes) {
192206
if (!cardUsableAtLocation(cardType, turn.player.location)) {
193207
continue;
194208
}
195-
if (canAfford(cardType)) {
209+
if (canAffordPurchase(cardType)) {
196210
yield Purchase(cardType: cardType);
197211
}
198212
if (canDefeat(cardType)) {
199213
yield Fight(cardType: cardType);
200214
}
215+
if (canAffordDevice(cardType)) {
216+
yield UseDevice(cardType: cardType);
217+
}
201218
}
202219
}
203220

test/clank_test.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,4 +448,18 @@ void main() {
448448
expect(turn.skill, 1);
449449
expect(turn.swords, 0);
450450
});
451+
452+
test('use device', () {
453+
var game = ClankGame(planners: [MockPlanner()]);
454+
var player = game.activePlayer;
455+
var board = game.board;
456+
board.dungeonRow = library.make('Ladder', 1);
457+
Turn turn = Turn(player: player);
458+
turn.skill = 3;
459+
game.executeAction(turn, UseDevice(cardType: board.dungeonRow.first.type));
460+
expect(board.dungeonDiscard.length, 1);
461+
expect(board.dungeonRow.length, 0);
462+
expect(turn.boots, 2);
463+
expect(turn.skill, 0);
464+
});
451465
}

0 commit comments

Comments
 (0)