# Coverage for thb/meta/cards/equipment.py : 73%

## 492 statements 352 run 140 missing 0 excluded 0 partial

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1# -*- coding: utf-8 -*-

2 from __future__ import annotations

3

4# -- stdlib --

5 from typing import Optional

6 import random

7

8# -- third party --

9# -- own --

10 from thb import actions

11 from thb.actions import ttags

12 from thb.cards import definition, equipment

13 from thb.cards.base import Card

14 from thb.meta.common import ui_meta

15 from utils.misc import BatchList

16

17

18# -- code --

19 def equip_iav(self, c, tl):

20 return (True, '配上好装备，不再掉节操！')

21

22

23 def suppress_launch_card_effect_string(self, act):

24 return None

25

26

27@ui_meta(equipment.WearEquipmentAction)

28 class WearEquipmentAction:

29

30 def effect_string(self, act):

31 return '|G【%s】|r装备了%s。' % (

32 act.target.ui_meta.name,

33 self.card_desc(act.associated_card),

34 )

35

36

37@ui_meta(equipment.WeaponReforgeHandler)

38 class WeaponReforgeHandler:

39 choose_option_prompt = '你希望重铸这张牌么？'

40 choose_option_buttons = (('重铸', True), ('装备', False))

41

42

43@ui_meta(equipment.ReforgeWeapon)

44 class ReforgeWeapon:

45 def effect_string(self, act):

46 return '|G【%s】|r重铸了%s。' % (

47 act.target.ui_meta.name,

48 self.card_desc(act.card),

49 )

50

51

52@ui_meta(definition.OpticalCloakCard)

53 class OpticalCloakCard:

54 # action_stage meta

55 name = '光学迷彩'

56 image = 'thb-card-opticalcloak'

57 image_small = 'thb-card-small-opticalcloak'

58 description = (

59 '|R光学迷彩|r\n\n'

60 '装备后：当你需要使用或打出|G擦弹|r时，可以进行一次判定，若结果为红，视为你使用或打出了一张|G擦弹|r。\n\n'

61 '|DB（画师：霏茶，CV：shourei小N）|r'

62 )

63

64 is_action_valid = equip_iav

65 effect_string = suppress_launch_card_effect_string

66

67

68@ui_meta(equipment.OpticalCloakSkill)

69 class OpticalCloakSkill:

70 # Skill

71 name = '光学迷彩'

72

73 def sound_effect(self, act):

74 return 'thb-cv-card_opticalcloak'

75

76 def effect_string(self, act):

77 return definition.GrazeCard.ui_meta.effect_string(act)

78

79

80@ui_meta(equipment.OpticalCloakHandler)

81 class OpticalCloakHandler:

82 # choose_option

83 choose_option_buttons = (('发动', True), ('不发动', False))

84 choose_option_prompt = '你要发动【光学迷彩】吗？'

85

86

87@ui_meta(equipment.OpticalCloak)

88 class OpticalCloak:

89 fatetell_display_name = '光学迷彩'

90

91 def effect_string_before(self, act):

92 return '|G【%s】|r祭起了|G光学迷彩|r…' % (

93 act.target.ui_meta.name,

94 )

95

96 def effect_string(self, act):

97 if act.succeeded:

98 return '效果拔群！'

99 else:

100 return '但是被看穿了…'

101

102

103@ui_meta(definition.MomijiShieldCard)

104 class MomijiShieldCard:

105 # action_stage meta

106 name = '天狗盾'

107 image = 'thb-card-momijishield'

108 image_small = 'thb-card-small-momijishield'

109 description = (

110 '|R天狗盾|r\n\n'

111 '装备后：黑色|G弹幕|r对你无效。\n\n'

112 '|DB（画师：霏茶）|r'

113 )

114

115 is_action_valid = equip_iav

116 effect_string = suppress_launch_card_effect_string

117

118

119@ui_meta(equipment.MomijiShieldSkill)

120 class MomijiShieldSkill:

121 # Skill

122 name = '天狗盾'

123

124

125@ui_meta(equipment.MomijiShield)

126 class MomijiShield:

127 def effect_string(self, act):

128 return '被|G天狗盾|r挡下了…'

129

130 def sound_effect(self, act):

131 return 'thb-cv-card_momijishield'

132

133

134 ufo_desc = (

135 '|R%s|r\n\n'

136 'UFO用来改变自己与其他角色之间的距离。\n'

137 '|B|R>> |r红色UFO为进攻用，当你计算和其他角色的距离时，在原有的基础上减少相应距离。两名角色之间的距离至少为1。\n'

138 '|B|R>> |r绿色UFO为防守用，当其他角色计算和你的距离时，在原有的基础上增加相应距离。\n'

139 '|B|R>> |r你可以同时装备两种UFO。\n\n'

140 '|DB（画师：霏茶）|r'

141)

142

143

144@ui_meta(definition.GreenUFOCard)

145 class GreenUFOCard:

146 # action_stage meta

147 name = '绿色UFO'

148 image = 'thb-card-greenufo'

149 image_small = 'thb-card-small-greenufo'

150 description = ufo_desc % name

151

152 is_action_valid = equip_iav

153 effect_string = suppress_launch_card_effect_string

154

155

156@ui_meta(equipment.GreenUFOSkill)

157 class GreenUFOSkill:

158 # Skill

159 name = '绿色UFO'

160 no_display = True

161

162

163@ui_meta(definition.RedUFOCard)

164 class RedUFOCard:

165 # action_stage meta

166 name = '红色UFO'

167 image = 'thb-card-redufo'

168 image_small = 'thb-card-small-redufo'

169 description = ufo_desc % name

170

171 is_action_valid = equip_iav

172 effect_string = suppress_launch_card_effect_string

173

174

175@ui_meta(equipment.RedUFOSkill)

176 class RedUFOSkill:

177 # Skill

178 name = '红色UFO'

179 no_display = True

180

181

182@ui_meta(definition.RoukankenCard)

183 class RoukankenCard:

184 # action_stage meta

185 name = '楼观剑'

186 image = 'thb-card-roukanken'

187 image_small = 'thb-card-small-roukanken'

188 description = (

189 '|R楼观剑|r\n'

190 '\n'

191 '攻击范围3，装备后：你使用的|G弹幕|r无视防具。\n'

192 '\n'

193 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

194 '\n'

195 '|DB（画师：霏茶）|r'

196 )

197 is_action_valid = equip_iav

198 effect_string = suppress_launch_card_effect_string

199

200

201@ui_meta(equipment.RoukankenSkill)

202 class RoukankenSkill:

203 # Skill

204 name = '楼观剑'

205

206

207@ui_meta(equipment.Roukanken)

208 class Roukanken:

209 def effect_string_apply(self, act):

210 return '没有什么防具是|G楼观剑|r斩不断的！'

211

212 def sound_effect(self, act):

213 return 'thb-cv-card_roukanken'

214

215

216@ui_meta(definition.ElementalReactorCard)

217 class ElementalReactorCard:

218 # action_stage meta

219 name = '八卦炉'

220 image = 'thb-card-reactor'

221 image_small = 'thb-card-small-reactor'

222 description = (

223 '|R八卦炉|r\n'

224 '\n'

225 '攻击范围1，装备后：出牌阶段你使用|G弹幕|r时不消耗干劲。\n'

226 '\n'

227 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

228 '\n'

229 '|DB（画师：霏茶）|r'

230 )

231

232 is_action_valid = equip_iav

233 effect_string = suppress_launch_card_effect_string

234

235

236@ui_meta(equipment.ElementalReactorSkill)

237 class ElementalReactorSkill:

238 # Skill

239 name = '八卦炉'

240

241

242@ui_meta(definition.UmbrellaCard)

243 class UmbrellaCard:

244 # action_stage meta

245 name = '阳伞'

246 image = 'thb-card-umbrella'

247 image_small = 'thb-card-small-umbrella'

248 description = (

249 '|R阳伞|r\n\n'

250 '装备后：符卡效果造成的伤害对你无效。\n\n'

251 '|DB（画师：霏茶）|r'

252 )

253

254 is_action_valid = equip_iav

255 effect_string = suppress_launch_card_effect_string

256

257

258@ui_meta(equipment.UmbrellaSkill)

259 class UmbrellaSkill:

260 # Skill

261 name = '紫的阳伞'

262

263

264@ui_meta(equipment.UmbrellaEffect)

265 class UmbrellaEffect:

266 def effect_string_before(self, act):

267 a = act.action

268 dmg = act.damage_act

269 card = getattr(a, 'associated_card', None)

270 if card and card.associated_action and isinstance(a, card.associated_action):

271 # Some skills changes action

272 s = '|G%s|r' % card.ui_meta.name

273 else:

274 s = ''

275

276 return '|G【%s】|r受到的%s效果被|G阳伞|r挡下了…' % (

277 dmg.target.ui_meta.name, s,

278 )

279

280 def sound_effect(self, act):

281 return 'thb-cv-card_umbrella'

282

283

284@ui_meta(definition.GungnirCard)

285 class GungnirCard:

286 # action_stage meta

287 name = '冈格尼尔'

288 image = 'thb-card-gungnir'

289 image_small = 'thb-card-small-gungnir'

290 description = (

291 '|R冈格尼尔|r\n'

292 '\n'

293 '攻击范围3，装备后：你可以将两张手牌当|G弹幕|r使用或打出。\n'

294 '\n'

295 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

296 '\n'

297 '|DB（画师：霏茶）|r'

298 )

299

300 is_action_valid = equip_iav

301 effect_string = suppress_launch_card_effect_string

302

303

304@ui_meta(equipment.GungnirSkill)

305 class GungnirSkill:

306 # Skill

307 name = '冈格尼尔'

308

309 def clickable(self):

310 me = self.me

311 return self.accept_cards([equipment.GungnirSkill(me)])

312

313 def is_complete(self, skill):

314 me = self.me

315 assert skill.is_card(equipment.GungnirSkill)

316 acards = skill.associated_cards

317 if len(acards) != 2:

318 return (False, '请选择2张手牌！')

319 elif any(c.resides_in not in (me.cards, me.showncards) for c in acards):

320 return (False, '只能使用手牌发动！')

321 return (True, '反正这条也看不到，偷个懒~~~')

322

323 def is_action_valid(self, sk, tl):

324 assert sk.is_card(equipment.GungnirSkill)

325 rst, reason = self.is_complete(sk)

326 if not rst:

327 return (rst, reason)

328 else:

329 return definition.AttackCard().ui_meta.is_action_valid(sk, tl)

330

331 def effect_string(self, act):

332 # for LaunchCard.effect_string

333 source = act.source

334 target = act.target

335 s = '|G【%s】|r发动了|G冈格尼尔|r之枪，将两张牌当作|G弹幕|r对|G【%s】|r使用。' % (

336 source.ui_meta.name,

337 target.ui_meta.name,

338 )

339 return s

340

341 def sound_effect(self, act):

342 return definition.AttackCard.ui_meta.sound_effect(act)

343

344

345@ui_meta(definition.ScarletRhapsodyCard)

346 class ScarletRhapsodyCard:

347 # action_stage meta

348 name = '绯想之剑'

349 image = 'thb-card-scarletrhapsodysword'

350 image_small = 'thb-card-small-scarletrhapsodysword'

351 description = (

352 '|R绯想之剑|r\n'

353 '\n'

354 '攻击范围4，装备后：当你使用的|G弹幕|r是你的最后一张手牌时，你可以为此|G弹幕|r指定至多三名目标。\n'

355 '\n'

356 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

357 '\n'

358 '|DB（画师：霏茶，CV：VV）|r'

359 )

360

361 is_action_valid = equip_iav

362 effect_string = suppress_launch_card_effect_string

363

364

365@ui_meta(equipment.ScarletRhapsodySkill)

366 class ScarletRhapsodySkill:

367 # Skill

368 name = '绯想之剑'

369

370 def clickable(self):

371 g = self.game

372 me = self.me

373 try:

374 act = g.action_stack[-1]

375 if isinstance(act, actions.ActionStage):

376 return act.target is me

377

378 except IndexError:

379 pass

380

381 return False

382

383 def is_action_valid(self, sk, tl):

384 assert sk.is_card(equipment.ScarletRhapsodySkill)

385 if not sk.check():

386 return (False, '请选择你的最后一张【弹幕】！')

387 else:

388 if not tl:

389 return (False, '请选择弹幕的目标（最多可以选择3名玩家）')

390

391 if self.me in tl:

392 return (True, '您真的要自残么？！')

393 else:

394 return (True, '全人类的绯想天！')

395

396 def effect_string(self, act: actions.LaunchCard) -> Optional[str]:

397 # for LaunchCard.ui_meta.effect_string

398 src = act.source

399 tl = BatchList(act.target_list)

400

401 return '全人类的绯想天，当然不能只打一个！于是|G【%s】|r选了|G【%s】|r一共%d个目标！' % (

402 src.ui_meta.name,

403 '】|r、|G【'.join(tl.ui_meta.name),

404 len(tl),

405 )

406

407 def sound_effect(self, act):

408 return 'thb-cv-card_srs'

409

410

411@ui_meta(definition.RepentanceStickCard)

412 class RepentanceStickCard:

413 # action_stage meta

414 name = '悔悟棒'

415 image = 'thb-card-repentancestick'

416 image_small = 'thb-card-small-repentancestick'

417 description = (

418 '|R悔悟棒|r\n'

419 '\n'

420 '攻击范围2，装备后：当你使用|G弹幕|r造成伤害时，你可以防止此伤害，改为依次弃置目标角色区域内的两张牌。\n'

421 '|B|R>> |r 区域内的牌包括手牌，装备区的牌和判定区的牌。\n'

422 '\n'

423 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

424 '\n'

425 '|DB（画师：霏茶，CV：shourei小N）|r'

426 )

427

428 is_action_valid = equip_iav

429 effect_string = suppress_launch_card_effect_string

430

431

432@ui_meta(equipment.RepentanceStickSkill)

433 class RepentanceStickSkill:

434 # Skill

435 name = '悔悟棒'

436

437

438@ui_meta(equipment.RepentanceStickHandler)

439 class RepentanceStickHandler:

440 # choose_option

441 choose_option_buttons = (('发动', True), ('不发动', False))

442 choose_option_prompt = '你要发动【悔悟棒】吗？'

443

444

445@ui_meta(equipment.RepentanceStick)

446 class RepentanceStick:

447 def effect_string_before(self, act):

448 return (

449 '|G【%s】|r用|G悔悟棒|r狠狠地敲了|G【%s】|r一通…'

450 ) % (

451 act.source.ui_meta.name,

452 act.target.ui_meta.name,

453

454 )

455

456 def effect_string(self, act: equipment.RepentanceStick) -> str:

457 cl = BatchList[Card](act.cards)

458 return '又抢过|G【%s】|r的|G%s|r扔了出去！' % (

459 act.target.ui_meta.name,

460 '|r和|G'.join(cl.ui_meta.name)

461 )

462

463 def sound_effect(self, act):

464 return 'thb-cv-card_repentancestick'

465

466

467@ui_meta(definition.IbukiGourdCard)

468 class IbukiGourdCard:

469 # action_stage meta

470 name = '伊吹瓢'

471 image = 'thb-card-ibukigourd'

472 image_small = 'thb-card-small-ibukigourd'

473 is_action_valid = equip_iav

474 effect_string = suppress_launch_card_effect_string

475

476 description = (

477 '|R伊吹瓢|r\n\n'

478 '装备后：获得立即|B喝醉|r状态。并且，若你在出牌阶段没有造成过伤害，在回合结束阶段获得|B喝醉|r状态。\n\n'

479 '|DB（画师：霏茶）|r'

480 )

481

482

483@ui_meta(equipment.IbukiGourdSkill)

484 class IbukiGourdSkill:

485 # Skill

486 name = '伊吹瓢'

487

488

489@ui_meta(definition.HouraiJewelCard)

490 class HouraiJewelCard:

491 # action_stage meta

492 name = '蓬莱玉枝'

493 image = 'thb-card-houraijewel'

494 image_small = 'thb-card-small-houraijewel'

495 description = (

496 '|R蓬莱玉枝|r\n'

497 '\n'

498 '攻击范围1。装备后，你使用的|G弹幕|r时，可以将弹幕的效果转化成如下的符卡效果：造成1点伤害。\n'

499 '\n'

500 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

501 '\n'

502 '|DB（画师：霏茶）|r'

503 )

504

505 is_action_valid = equip_iav

506 effect_string = suppress_launch_card_effect_string

507

508

509@ui_meta(equipment.HouraiJewelSkill)

510 class HouraiJewelSkill:

511 # Skill

512 name = '蓬莱玉枝'

513

514

515@ui_meta(equipment.HouraiJewelHandler)

516 class HouraiJewelHandler:

517 # choose_option

518 choose_option_buttons = (('发动', True), ('不发动', False))

519 choose_option_prompt = '你要发动【蓬莱玉枝】吗？'

520

521

522@ui_meta(equipment.HouraiJewelAttack)

523 class HouraiJewelAttack:

524 def effect_string_apply(self, act):

525 return (

526 '|G【%s】|r发动了|G蓬莱玉枝|r，包裹着魔法核心的弹幕冲向了|G【%s】|r！'

527 ) % (

528 act.source.ui_meta.name,

529 act.target.ui_meta.name,

530 )

531

532

533@ui_meta(definition.MaidenCostumeCard)

534 class MaidenCostumeCard:

535 # action_stage meta

536 name = '巫女服'

537 image = 'thb-card-maidencostume'

538 image_small = 'thb-card-small-maidencostume'

539 description = (

540 '|R巫女服|r\n\n'

541 '装备后：当你成为一张符卡的目标时，你可以进行一次判定：若判定牌点数为9到K，则视为你使用了一张|G好人卡|r。\n\n'

542 '|DB（画师：霏茶，CV：VV）|r'

543 )

544 is_action_valid = equip_iav

545 effect_string = suppress_launch_card_effect_string

546

547

548@ui_meta(equipment.MaidenCostume)

549 class MaidenCostume:

550 # Skill

551 name = '巫女服'

552

553 def sound_effect(self, act):

554 return 'thb-cv-card_maidencostume'

555

556

557@ui_meta(equipment.MaidenCostumeHandler)

558 class MaidenCostumeHandler:

559 # choose_option

560 choose_option_buttons = (('发动', True), ('不发动', False))

561 choose_option_prompt = '你要发动【巫女服】吗？'

562

563

564@ui_meta(equipment.MaidenCostumeAction)

565 class MaidenCostumeAction:

566 fatetell_display_name = '巫女服'

567

568 def effect_string_before(self, act):

569 return (

570 '|G【%s】|r穿了|G巫女服|r，春度爆表，不怕符卡！'

571 ) % (

572 act.source.ui_meta.name,

573 )

574

575 def effect_string(self, act):

576 if not act.succeeded:

577 return (

578 '好像|G【%s】|r的春度还是不够用…'

579 ) % (

580 act.source.ui_meta.name,

581 )

582

583

584@ui_meta(definition.HakuroukenCard)

585 class HakuroukenCard:

586 # action_stage meta

587 name = '白楼剑'

588 image = 'thb-card-hakurouken'

589 image_small = 'thb-card-small-hakurouken'

590 description = (

591 '|R白楼剑|r\n\n'

592 '攻击范围2，装备后：当你使用的草花色|G弹幕|r指定一名目标角色后，你可以令其选择一项：\n'

593 '|B|R>> |r弃置一张手牌。\n'

594 '|B|R>> |r令你摸一张牌。\n'

595 '\n'

596 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

597 '\n'

598 '|DB（画师：霏茶，CV：小羽）|r'

599 )

600 is_action_valid = equip_iav

601 effect_string = suppress_launch_card_effect_string

602

603

604@ui_meta(equipment.HakuroukenSkill)

605 class HakuroukenSkill:

606 # Skill

607 name = '白楼剑'

608

609

610@ui_meta(equipment.Hakurouken)

611 class Hakurouken:

612 # choose_card

613 def choose_card_text(self, act, cards):

614 if act.cond(cards):

615 return (True, '弃置这张牌')

616 else:

617 return (False, '请弃掉一张牌（否则对方摸一张牌）')

618

619 def effect_string_before(self, act):

620 return (

621 '|G【%s】|r祭起了|G白楼剑|r，试图斩断|G【%s】|r的迷惘！'

622 ) % (

623 act.source.ui_meta.name,

624 act.target.ui_meta.name,

625 )

626

627 def effect_string(self, act):

628 if act.peer_action == 'drop':

629 return '|G【%s】|r弃置了一张牌。' % act.target.ui_meta.name

630 else:

631 return None # DrawCards has it's own prompt

632

633 def sound_effect(self, act):

634 return 'thb-cv-card_hakurouken'

635

636

637@ui_meta(equipment.HakuroukenHandler)

638 class HakuroukenHandler:

639 # choose_option

640 choose_option_buttons = (('发动', True), ('不发动', False))

641 choose_option_prompt = '你要发动【白楼剑】吗？'

642

643

644@ui_meta(definition.AyaRoundfanCard)

645 class AyaRoundfanCard:

646 # action_stage meta

647 name = '团扇'

648 image = 'thb-card-ayaroundfan'

649 image_small = 'thb-card-small-ayaroundfan'

650 description = (

651 '|R团扇|r\n'

652 '\n'

653 '攻击距离5，装备后：当你使用的|G弹幕|r对目标角色造成伤害后，你可以弃置一张手牌，然后弃置其装备区里的一张牌。\n'

654 '\n'

655 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

656 '\n'

657 '|DB（画师：霏茶，CV：VV）|r'

658 )

659 is_action_valid = equip_iav

660 effect_string = suppress_launch_card_effect_string

661

662

663@ui_meta(equipment.AyaRoundfanSkill)

664 class AyaRoundfanSkill:

665 # Skill

666 name = '团扇'

667

668

669@ui_meta(equipment.AyaRoundfanHandler)

670 class AyaRoundfanHandler:

671 # choose_card

672 def choose_card_text(self, act, cards):

673 if act.cond(cards):

674 return (True, '这种妨碍拍摄的东西，统统脱掉！')

675 else:

676 return (False, '请弃掉一张手牌发动团扇（否则不发动）')

677

678

679@ui_meta(equipment.AyaRoundfan)

680 class AyaRoundfan:

681 def effect_string_before(self, act):

682 return (

683 '|G【%s】|r觉得手中的|G团扇|r用起来好顺手，便加大力度试了试…'

684 ) % (

685 act.source.ui_meta.name,

686 )

687

688 def effect_string(self, act):

689 return (

690 '于是|G【%s】|r的|G%s|r就飞了出去！'

691 ) % (

692 act.target.ui_meta.name,

693 act.card.ui_meta.name,

694 )

695

696 def sound_effect(self, act):

697 return random.choice([

698 'thb-cv-card_roundfan1',

699 'thb-cv-card_roundfan2',

700 ])

701

702

703@ui_meta(definition.NenshaPhoneCard)

704 class NenshaPhoneCard:

705 # action_stage meta

706 name = '念写机'

707 image = 'thb-card-nenshaphone'

708 image_small = 'thb-card-small-nenshaphone'

709 description = (

710 '|R念写机|r\n'

711 '\n'

712 '攻击距离4，装备后：当你使用的|G弹幕|r对目标角色造成伤害后，可以将其两张手牌置入明牌区。\n'

713 '\n'

714 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

715 '\n'

716 '|DB（画师：霏茶）|r'

717

718 )

719 is_action_valid = equip_iav

720 effect_string = suppress_launch_card_effect_string

721

722

723@ui_meta(equipment.NenshaPhoneSkill)

724 class NenshaPhoneSkill:

725 # Skill

726 name = '念写机'

727

728

729@ui_meta(equipment.NenshaPhoneHandler)

730 class NenshaPhoneHandler:

731 # choose_option

732 choose_option_buttons = (('发动', True), ('不发动', False))

733 choose_option_prompt = '你要发动【念写机】吗？'

734

735

736@ui_meta(equipment.NenshaPhone)

737 class NenshaPhone:

738 def effect_string(self, act):

739 return (

740 '|G【%s】|r表示，将|G【%s】|r推倒后拍摄胖次，是记者的自我修养中不可或缺的一部分。'

741 ) % (

742 act.source.ui_meta.name,

743 act.target.ui_meta.name,

744 )

745

746 def sound_effect(self, act):

747 return 'thb-cv-card_nenshaphone'

748

749

750@ui_meta(definition.LaevateinCard)

751 class LaevateinCard:

752 # action_stage meta

753 name = '莱瓦汀'

754 image = 'thb-card-laevatein'

755 image_small = 'thb-card-small-laevatein'

756 description = (

757 '|R莱瓦汀|r\n'

758 '\n'

759 '攻击距离3，装备后：当你使用的|G弹幕|r被目标角色使用的|G擦弹|r抵消时，你可以弃置两张牌，令此|G弹幕|r依然生效。\n'

760 '\n'

761 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

762 '\n'

763 '|DB（画师：霏茶，CV：VV）|r'

764 )

765 is_action_valid = equip_iav

766 effect_string = suppress_launch_card_effect_string

767

768

769@ui_meta(equipment.LaevateinSkill)

770 class LaevateinSkill:

771 # Skill

772 name = '莱瓦汀'

773

774

775@ui_meta(equipment.LaevateinHandler)

776 class LaevateinHandler:

777 # choose_card

778 def choose_card_text(self, act, cards):

779 if act.cond(cards):

780 return (True, '灭世之炎岂能轻易闪过！')

781 else:

782 return (False, '请弃掉两张牌发动莱瓦汀（否则不发动）')

783

784

785@ui_meta(equipment.Laevatein)

786 class Laevatein:

787 def effect_string_before(self, act):

788 return '|G莱瓦汀|r的灭世之炎岂能轻易闪过！'

789

790 def sound_effect(self, act):

791 return 'thb-cv-card_laevatein'

792

793

794@ui_meta(definition.DeathSickleCard)

795 class DeathSickleCard:

796 # action_stage meta

797 name = '死神之镰'

798 image = 'thb-card-deathsickle'

799 image_small = 'thb-card-small-deathsickle'

800 description = (

801 '|R死神之镰|r\n'

802 '\n'

803 '攻击范围2，装备后：当你使用的【弹幕】对目标角色造成伤害时，若其没有手牌，此伤害+1。\n'

804 '\n'

805 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

806 '\n'

807 '|DB（画师：霏茶，CV：小羽）|r'

808 )

809 is_action_valid = equip_iav

810 effect_string = suppress_launch_card_effect_string

811

812

813@ui_meta(equipment.DeathSickleSkill)

814 class DeathSickleSkill:

815 # Skill

816 name = '死神之镰'

817

818

819@ui_meta(equipment.DeathSickle)

820 class DeathSickle:

821 def effect_string(self, act):

822 return (

823 '|G【%s】|r看到|G【%s】|r一副丧家犬的模样，'

824 '手中的|G死神之镰|r不自觉地一狠…'

825 ) % (

826 act.source.ui_meta.name,

827 act.target.ui_meta.name,

828 )

829

830 def sound_effect(self, act):

831 return 'thb-cv-card_deathsickle'

832

833

834@ui_meta(definition.KeystoneCard)

835 class KeystoneCard:

836 # action_stage meta

837 name = '要石'

838 image = 'thb-card-keystone'

839 image_small = 'thb-card-small-keystone'

840 description = (

841 '|R要石|r\n\n'

842 '特殊的绿色UFO装备，距离+1\n'

843 '装备后跳过【罪袋】对你的结算。\n\n'

844 '|DB（画师：霏茶，CV：shourei小N）|r'

845 )

846 is_action_valid = equip_iav

847 effect_string = suppress_launch_card_effect_string

848

849

850@ui_meta(equipment.KeystoneSkill)

851 class KeystoneSkill:

852 # Skill

853 name = '要石'

854

855

856@ui_meta(equipment.Keystone)

857 class Keystone:

858 def effect_string(self, act):

859 return '|G【%s】|r站在|G要石|r上，照着|G罪袋|r的脸一脚踹了下去！' % (

860 act.target.ui_meta.name

861 )

862

863 def sound_effect(self, act):

864 return 'thb-cv-card_keystone'

865

866

867@ui_meta(definition.WitchBroomCard)

868 class WitchBroomCard:

869 # action_stage meta

870 name = '魔女扫把'

871 image = 'thb-card-witchbroom'

872 image_small = 'thb-card-small-witchbroom'

873 is_action_valid = equip_iav

874 effect_string = suppress_launch_card_effect_string

875 description = (

876 '|R魔女扫把|r\n\n'

877 '特殊的红色UFO装备，距离-2。\n\n'

878 '|DB（画师：霏茶）|r'

879 )

880

881

882@ui_meta(equipment.WitchBroomSkill)

883 class WitchBroomSkill:

884 # Skill

885 no_display = True

886

887

888@ui_meta(definition.YinYangOrbCard)

889 class YinYangOrbCard:

890 # action_stage meta

891 name = '阴阳玉'

892 image = 'thb-card-yinyangorb'

893 image_small = 'thb-card-small-yinyangorb'

894 description = (

895 '|R阴阳玉|r\n\n'

896 '装备后：在你的判定牌生效前，你可以用装备区内的|G阴阳玉|r替换之。\n\n'

897 '|DB（画师：霏茶）|r'

898 )

899 is_action_valid = equip_iav

900 effect_string = suppress_launch_card_effect_string

901

902

903@ui_meta(equipment.YinYangOrbSkill)

904 class YinYangOrbSkill:

905 # Skill

906 name = '阴阳玉'

907

908

909@ui_meta(equipment.YinYangOrbHandler)

910 class YinYangOrbHandler:

911 # choose_option

912 choose_option_buttons = (('替换', True), ('不替换', False))

913 choose_option_prompt = '你要使用【阴阳玉】替换当前的判定牌吗？'

914

915

916@ui_meta(equipment.YinYangOrb)

917 class YinYangOrb:

918 def effect_string(self, act):

919 return '|G【%s】|r用|G%s|r替换了她的判定牌。' % (

920 act.target.ui_meta.name,

921 self.card_desc(act.card),

922 )

923

924

925@ui_meta(definition.SuwakoHatCard)

926 class SuwakoHatCard:

927 # action_stage meta

928 name = '青蛙帽'

929 image = 'thb-card-suwakohat'

930 image_small = 'thb-card-small-suwakohat'

931 description = (

932 '|R青蛙帽|r\n\n'

933 '装备后：手牌上限+2。\n\n'

934 '|DB（画师：霏茶，CV：VV）|r'

935 )

936 is_action_valid = equip_iav

937 effect_string = suppress_launch_card_effect_string

938

939

940@ui_meta(equipment.SuwakoHatSkill)

941 class SuwakoHatSkill:

942 # Skill

943 name = '青蛙帽'

944

945

946@ui_meta(equipment.SuwakoHatEffect)

947 class SuwakoHatEffect:

948 def sound_effect(self, act):

949 return 'thb-cv-card_suwakohat'

950

951

952@ui_meta(definition.YoumuPhantomCard)

953 class YoumuPhantomCard:

954 # action_stage meta

955 name = '半灵'

956 image = 'thb-card-phantom'

957 image_small = 'thb-card-small-phantom'

958 description = (

959 '|R半灵|r\n\n'

960 '装备后：增加1点体力上限，当失去装备区里的【半灵】时，你回复1点体力。\n\n'

961 '|DB（画师：霏茶，CV：小羽）|r'

962 )

963

964 is_action_valid = equip_iav

965 effect_string = suppress_launch_card_effect_string

966

967

968@ui_meta(equipment.YoumuPhantomSkill)

969 class YoumuPhantomSkill:

970 # Skill

971 name = '半灵'

972

973

974@ui_meta(equipment.YoumuPhantomHeal)

975 class YoumuPhantomHeal:

976 def sound_effect(self, act):

977 return 'thb-cv-card_phantom'

978

979

980@ui_meta(definition.IceWingCard)

981 class IceWingCard:

982 # action_stage meta

983 name = '⑨的翅膀'

984 image = 'thb-card-icewing'

985 image_small = 'thb-card-small-icewing'

986 description = (

987 '|R⑨的翅膀|r\n\n'

988 '特殊的红色UFO装备，距离-1。\n\n'

989 '装备后：|G封魔阵|r和|G冻青蛙|r对你无效。\n\n'

990 '|DB（画师：霏茶，CV：VV）|r'

991 )

992

993 is_action_valid = equip_iav

994 effect_string = suppress_launch_card_effect_string

995

996

997@ui_meta(equipment.IceWingSkill)

998 class IceWingSkill:

999 # Skill

1000 name = '⑨的翅膀'

1001

1002

1003@ui_meta(equipment.IceWing)

1004 class IceWing:

1005 def effect_string(self, act):

1006 return '|G【%s】|r借着|G⑨的翅膀|r飞了出来，|G%s|r没起到什么作用。' % (

1007 act.target.ui_meta.name,

1008 act.action.associated_card.ui_meta.name,

1009 )

1010

1011 def sound_effect(self, act):

1012 tgt = act.target

1013 if ttags(tgt)['__icewing_se']:

1014 return None

1015

1016 ttags(tgt)['__icewing_se'] = True

1017 return 'thb-cv-card_icewing'

1018

1019

1020@ui_meta(definition.GrimoireCard)

1021 class GrimoireCard:

1022 # action_stage meta

1023 name = '魔导书'

1024 image = 'thb-card-grimoire'

1025 image_small = 'thb-card-small-grimoire'

1026 description = (

1027 '|R魔导书|r\n'

1028 '\n'

1029 '攻击距离1，装备后，你可以消耗一点干劲并将一张牌按照以下规则使用：\n'

1030 '|B|R>> |r黑桃♠视为|G百鬼夜行|r。\n'

1031 '|B|R>> |r红桃♥视为|G宴会|r。\n'

1032 '|B|R>> |r梅花♣视为|G地图炮|r。\n'

1033 '|B|R>> |r方片♦视为|G五谷丰登|r。\n'

1034 '\n'

1035 '|R出牌阶段你可以消耗1点干劲重铸手牌中的武器|r\n'

1036 '\n'

1037 '|DB（画师：霏茶，CV：shourei小N）|r'

1038 )

1039 is_action_valid = equip_iav

1040 effect_string = suppress_launch_card_effect_string

1041

1042

1043@ui_meta(equipment.GrimoireSkill)

1044 class GrimoireSkill:

1045 # Skill

1046 name = '魔导书'

1047

1048 def clickable(self):

1049 g = self.game

1050 me = self.me

1051 t = me.tags

1052 if t['grimoire_tag'] >= t['turn_count']:

1053 return False

1054

1055 try:

1056 act = g.action_stack[-1]

1057 if isinstance(act, actions.ActionStage):

1058 if me.tags['freeattack'] >= me.tags['turn_count']:

1059 return True

1060

1061 if me.tags['vitality'] > 0:

1062 return True

1063

1064 if me.has_skill(equipment.ElementalReactorSkill):

1065 return True

1066

1067 except IndexError:

1068 pass

1069

1070 return False

1071

1072 def is_action_valid(self, sk, tl):

1073 assert sk.is_card(equipment.GrimoireSkill)

1074 acards = sk.associated_cards

1075 if not (len(acards)) == 1:

1076 return (False, '请选择一张牌')

1077 else:

1078 s = sk.lookup_tbl[acards[0].suit].ui_meta.name

1079 return (True, '发动【%s】' % s)

1080

1081 def effect_string(self, act):

1082 # for LaunchCard.ui_meta.effect_string

1083 source = act.source

1084 card = act.card

1085 return (

1086 '|G【%s】|r抓起一张牌放入|G魔导书|r' +

1087 '，念动咒语，发动了|G%s|r。'

1088 ) % (

1089 source.ui_meta.name,

1090 card.lookup_tbl[card.associated_cards[0].suit].ui_meta.name

1091 )

1092

1093 def sound_effect(self, act):

1094 return 'thb-cv-card_grimoire'

1095

1096

1097@ui_meta(equipment.SinsackHatAction)

1098 class SinsackHatAction:

1099 fatetell_display_name = '头套'

1100

1101 def effect_string_before(self, act):

1102 return '看着戴着|G头套|r的|G【%s】|r，真正的的罪袋们都兴奋了起来！' % (

1103 act.target.ui_meta.name,

1104 )

1105

1106

1107@ui_meta(equipment.SinsackHat)

1108 class SinsackHat:

1109 # Skill

1110 name = '头套'

1111

1112

1113@ui_meta(definition.SinsackHatCard)

1114 class SinsackHatCard:

1115 # action_stage meta

1116 name = '头套'

1117 image = 'thb-card-sinsackhat'

1118 image_small = 'thb-card-small-sinsackhat'

1119 description = (

1120 '|R罪袋的头套|r\n\n'

1121 '对距离2以内的一名角色使用。\n'

1122 '装备|G罪袋的头套|r的角色需在判定阶段后进行一次判定，若为黑桃1-8，则目标角色受到2点伤害，并且将|G罪袋的头套|r收入手牌。\n'

1123 '|DB（画师：霏茶，CV：大白）|r'

1124 )

1125

1126 def is_action_valid(self, c, tl):

1127 if not tl:

1128 return (False, '请选择目标')

1129 t = tl[0]

1130 if self.me is t:

1131 return (True, '真的要自己戴上吗？')

1132 return (True, '是这样的，这个不是胖次……不不，真的没有胖次')

1133

1134 effect_string = suppress_launch_card_effect_string