Skip to content

Commit 6c8a354

Browse files
authored
Merge pull request #88 from neph1/update-v0.32.0
combat points and replenish
2 parents 31bb7c3 + 35ef32a commit 6c8a354

File tree

7 files changed

+76
-6
lines changed

7 files changed

+76
-6
lines changed

tale/accounts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ def _create_database(self) -> None:
110110
strength integer NOT NULL,
111111
dexterity integer NOT NULL,
112112
weapon_skills varchar NOT NULL,
113+
combat_points integer NOT NULL,
114+
max_combat_points integer NOT NULL,
113115
FOREIGN KEY(account) REFERENCES Account(id)
114116
);
115117
""")

tale/base.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,8 @@ def __init__(self) -> None:
975975
self.dexterity = 3
976976
self.unarmed_attack = Weapon(UnarmedAttack.FISTS.name, weapon_type=WeaponType.UNARMED)
977977
self.weapon_skills = {} # type: Dict[WeaponType, int] # weapon type -> skill level
978+
self.combat_points = 0 # combat points
979+
self.max_combat_points = 5 # max combat points
978980

979981
def __repr__(self):
980982
return "<Stats: %s>" % self.__dict__
@@ -1007,6 +1009,22 @@ def get_weapon_skill(self, weapon_type: WeaponType) -> int:
10071009
def set_weapon_skill(self, weapon_type: WeaponType, value: int) -> None:
10081010
self.weapon_skills[weapon_type] = value
10091011

1012+
def replenish_hp(self, amount: int = None) -> None:
1013+
if amount:
1014+
self.hp += amount
1015+
else:
1016+
self.hp = self.max_hp
1017+
if self.hp > self.max_hp:
1018+
self.hp = self.max_hp
1019+
1020+
def replenish_combat_points(self, amount: int = None) -> None:
1021+
if amount:
1022+
self.combat_points += amount
1023+
else:
1024+
self.combat_points = self.max_combat_points
1025+
if self.combat_points > self.max_combat_points:
1026+
self.combat_points = self.max_combat_points
1027+
10101028
class Living(MudObject):
10111029
"""
10121030
A living entity in the mud world (also known as an NPC).
@@ -1422,6 +1440,10 @@ def locate_item(self, name: str, include_inventory: bool=True, include_location:
14221440

14231441
def start_attack(self, defender: 'Living', target_body_part: wearable.WearLocation= None) -> combat.Combat:
14241442
"""Starts attacking the given living for one round."""
1443+
if self.stats.combat_points < 1:
1444+
self.tell("You are too tired to attack.")
1445+
return
1446+
self.stats.combat_points -= 1
14251447
attacker_name = lang.capital(self.title)
14261448
victim_name = lang.capital(defender.title)
14271449
attackers = [self]

tale/combat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def _calculate_block_success(self, actor1: 'base.Living', actor2: 'base.Living')
4040
if actor2.wielding.type in weapon_type.ranged:
4141
# can't block with a ranged weapon
4242
return 100
43-
return random.randrange(0, 100) - actor2.stats.get_weapon_skill(actor2.wielding.type)
43+
return random.randrange(0, 100) - actor2.stats.get_weapon_skill(actor2.wielding.type) * (0.8 if actor2.stats.combat_points < 1 else 1)
4444

4545
def _calculate_weapon_bonus(self, actor: 'base.Living'):
4646
weapon = actor.wielding

tale/driver.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ def start(self, game_file_or_path: str) -> None:
320320
x._bind_target(self.zones)
321321
self.unbound_exits = []
322322
sys.excepthook = util.excepthook # install custom verbose crash reporter
323+
self.register_periodicals(self)
323324
self.start_main_loop() # doesn't exit! (unless game is killed)
324325
self._stop_driver()
325326

@@ -958,4 +959,10 @@ def build_location(self, targetLocation: base.Location, zone: Zone, player: play
958959
return True
959960

960961
def do_on_player_death(self, player: player.Player) -> None:
961-
pass
962+
pass
963+
964+
@util.call_periodically(10)
965+
def replenish(self):
966+
for player in self.all_players.values():
967+
player.player.stats.replenish_hp(1)
968+
player.player.stats.replenish_combat_points(1)

tale/player.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from .tio.iobase import strip_text_styles, IoAdapterBase
2323
from .vfs import VirtualFileSystem, Resource
2424
from tale.player_utils import TextBuffer
25+
from tale.util import call_periodically
2526

2627

2728
class Player(base.Living, pubsub.Listener):
@@ -408,5 +409,4 @@ def destroy(self) -> None:
408409
self.io = None # type: ignore
409410
if self.player:
410411
self.player.destroy(ctx)
411-
self.player = None # type: ignore
412-
412+
self.player = None # type: ignore

tests/test_combat.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from tale.llm.LivingNpc import LivingNpc
55
from tale.combat import Combat
66
from tale.llm.contexts.CombatContext import CombatContext
7+
from tale.player import Player
78
from tale.races import BodyType
89
from tale.weapon_type import WeaponType
910
from tale.wearable import WearLocation
@@ -16,8 +17,6 @@
1617
class TestCombat():
1718

1819
def test_resolve_attack(self):
19-
20-
2120
attacker = LivingNpc(name='attacker', gender='m', age=42, personality='A fierce fighter')
2221
defender = LivingNpc(name='defender', gender='f', age=37, personality='A fierce fighter')
2322

@@ -238,3 +237,11 @@ def test_resolve_attack_group(self):
238237
self._assert_combat(attacker, defender, text)
239238
assert('attacker hits' in text or 'attacker performs a critical hit' in text)
240239
assert('attacker2 hits' in text or 'attacker2 performs a critical hit' in text)
240+
241+
def test_start_attack_no_combat_points(self):
242+
attacker = Player(name='att', gender='m')
243+
attacker.stats.combat_points = 0
244+
defender = LivingNpc(name='lucky rat', gender='m', age=2, personality='A squeeky fighter')
245+
246+
assert attacker.start_attack(defender) == None
247+
assert ['You are too tired to attack.\n'] == attacker.test_get_output_paragraphs()

tests/test_stats.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
3+
from tale.base import Stats
4+
5+
6+
class TestStats:
7+
8+
def test_replenish_hp(self):
9+
stats = Stats()
10+
stats.max_hp = 100
11+
stats.hp = 0
12+
13+
stats.replenish_hp(10)
14+
15+
assert stats.hp == 10
16+
17+
stats.replenish_hp()
18+
19+
assert stats.hp == 100
20+
21+
def test_replenish_combat_points(self):
22+
stats = Stats()
23+
stats.max_combat_points = 100
24+
stats.combat_points = 0
25+
26+
stats.replenish_combat_points(10)
27+
28+
assert stats.combat_points == 10
29+
30+
stats.replenish_combat_points()
31+
32+
assert stats.combat_points == 100

0 commit comments

Comments
 (0)