blob: c1c9f3055bdbbdfa1b639271987f8341d02fcf90 (
plain)
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
|
from typing import Any
from dataclasses import dataclass
from items import Weapon
from game import d, Roll
from character import Character
@dataclass
class Attack:
attacker: Character
target: Any
weapon: Weapon
strike_type="melee"
previous_attacks: int = 0
distance: int = 0
sneak: bool = False
def bonus(self):
return self.attacker.attack_bonus(self.weapon, self.strike_type) + self.map()
def roll(self):
ac = self.target.ac()
return d(20).apply(Roll.check, ac, self.bonus())
def strike(self):
def strike_dmg(check):
return self.damage(check)
return self.roll().apply(strike_dmg)
def damage_bonus(self):
return self.attacker.attack_damage_bonus(self.weapon, self.strike_type)
def __str__(self):
res = ""
if self.sneak:
res += "Sneak "
ac = self.target.ac()
bonus = self.bonus()
res += f"{self.strike_type} attack{self.previous_attacks+1} "
res += f"{bonus:+} vs AC {ac}: {10+bonus-ac:+}; "
res += Roll.short_str(self.roll())
res += f" Dmg: {self.strike().expected()}"
return res
def damage(self, check=Roll.Success):
persistant_damage_factor = 3 + 1/3
wp = self.weapon
dmg_bonus = self.damage_bonus()
if self.sneak:
dmg_bonus += self.attacker.sneak_attack()
if wp.backstabber:
dmg_bonus += 1
if wp.potency >= 3:
dmg_bonus += 1
if wp.twin and self.previous_attacks > 0:
dmg_bonus += wp.dice_count()
if check == Roll.Success:
return wp.dice_count() * d(wp.main_die) + dmg_bonus
if check == Roll.Crit:
dmg = None
if wp.fatal is not None and wp.fatal > 0:
dmg = (wp.dice_count() + 1) * d(wp.fatal)
else:
dmg = wp.dice_count() * d(wp.main_die)
dmg = 2 * (dmg+dmg_bonus)
if wp.deadly is not None and wp.deadly > 0:
dmg += max(1, wp.dice_count()-1) * d(wp.deadly)
if wp.group == "crossbow":
dmg += persistant_damage_factor * d(8).expected()
elif wp.group == "dart" or wp.group == "knife":
dmg += persistant_damage_factor * d(6).expected()
elif wp.group == "dagger":
dmg += persistant_damage_factor * d(6).expected()
elif wp.group == "pick":
dmg += 2 * wp.dice_count()
return dmg
return 0
def range_penalty(self):
return 0
def map(self):
factor = max(0, min(2, self.previous_attacks))
if self.weapon.agile:
return factor * -4
return factor * -5
|