Skip to content

Commit

Permalink
Merge pull request #88 from neph1/update-v0.32.0
Browse files Browse the repository at this point in the history
combat points and replenish
  • Loading branch information
neph1 authored Jul 17, 2024
2 parents 31bb7c3 + 35ef32a commit 6c8a354
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 6 deletions.
2 changes: 2 additions & 0 deletions tale/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ def _create_database(self) -> None:
strength integer NOT NULL,
dexterity integer NOT NULL,
weapon_skills varchar NOT NULL,
combat_points integer NOT NULL,
max_combat_points integer NOT NULL,
FOREIGN KEY(account) REFERENCES Account(id)
);
""")
Expand Down
22 changes: 22 additions & 0 deletions tale/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,8 @@ def __init__(self) -> None:
self.dexterity = 3
self.unarmed_attack = Weapon(UnarmedAttack.FISTS.name, weapon_type=WeaponType.UNARMED)
self.weapon_skills = {} # type: Dict[WeaponType, int] # weapon type -> skill level
self.combat_points = 0 # combat points
self.max_combat_points = 5 # max combat points

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

def replenish_hp(self, amount: int = None) -> None:
if amount:
self.hp += amount
else:
self.hp = self.max_hp
if self.hp > self.max_hp:
self.hp = self.max_hp

def replenish_combat_points(self, amount: int = None) -> None:
if amount:
self.combat_points += amount
else:
self.combat_points = self.max_combat_points
if self.combat_points > self.max_combat_points:
self.combat_points = self.max_combat_points

class Living(MudObject):
"""
A living entity in the mud world (also known as an NPC).
Expand Down Expand Up @@ -1422,6 +1440,10 @@ def locate_item(self, name: str, include_inventory: bool=True, include_location:

def start_attack(self, defender: 'Living', target_body_part: wearable.WearLocation= None) -> combat.Combat:
"""Starts attacking the given living for one round."""
if self.stats.combat_points < 1:
self.tell("You are too tired to attack.")
return
self.stats.combat_points -= 1
attacker_name = lang.capital(self.title)
victim_name = lang.capital(defender.title)
attackers = [self]
Expand Down
2 changes: 1 addition & 1 deletion tale/combat.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def _calculate_block_success(self, actor1: 'base.Living', actor2: 'base.Living')
if actor2.wielding.type in weapon_type.ranged:
# can't block with a ranged weapon
return 100
return random.randrange(0, 100) - actor2.stats.get_weapon_skill(actor2.wielding.type)
return random.randrange(0, 100) - actor2.stats.get_weapon_skill(actor2.wielding.type) * (0.8 if actor2.stats.combat_points < 1 else 1)

def _calculate_weapon_bonus(self, actor: 'base.Living'):
weapon = actor.wielding
Expand Down
9 changes: 8 additions & 1 deletion tale/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ def start(self, game_file_or_path: str) -> None:
x._bind_target(self.zones)
self.unbound_exits = []
sys.excepthook = util.excepthook # install custom verbose crash reporter
self.register_periodicals(self)
self.start_main_loop() # doesn't exit! (unless game is killed)
self._stop_driver()

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

def do_on_player_death(self, player: player.Player) -> None:
pass
pass

@util.call_periodically(10)
def replenish(self):
for player in self.all_players.values():
player.player.stats.replenish_hp(1)
player.player.stats.replenish_combat_points(1)
4 changes: 2 additions & 2 deletions tale/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from .tio.iobase import strip_text_styles, IoAdapterBase
from .vfs import VirtualFileSystem, Resource
from tale.player_utils import TextBuffer
from tale.util import call_periodically


class Player(base.Living, pubsub.Listener):
Expand Down Expand Up @@ -408,5 +409,4 @@ def destroy(self) -> None:
self.io = None # type: ignore
if self.player:
self.player.destroy(ctx)
self.player = None # type: ignore

self.player = None # type: ignore
11 changes: 9 additions & 2 deletions tests/test_combat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from tale.llm.LivingNpc import LivingNpc
from tale.combat import Combat
from tale.llm.contexts.CombatContext import CombatContext
from tale.player import Player
from tale.races import BodyType
from tale.weapon_type import WeaponType
from tale.wearable import WearLocation
Expand All @@ -16,8 +17,6 @@
class TestCombat():

def test_resolve_attack(self):


attacker = LivingNpc(name='attacker', gender='m', age=42, personality='A fierce fighter')
defender = LivingNpc(name='defender', gender='f', age=37, personality='A fierce fighter')

Expand Down Expand Up @@ -238,3 +237,11 @@ def test_resolve_attack_group(self):
self._assert_combat(attacker, defender, text)
assert('attacker hits' in text or 'attacker performs a critical hit' in text)
assert('attacker2 hits' in text or 'attacker2 performs a critical hit' in text)

def test_start_attack_no_combat_points(self):
attacker = Player(name='att', gender='m')
attacker.stats.combat_points = 0
defender = LivingNpc(name='lucky rat', gender='m', age=2, personality='A squeeky fighter')

assert attacker.start_attack(defender) == None
assert ['You are too tired to attack.\n'] == attacker.test_get_output_paragraphs()
32 changes: 32 additions & 0 deletions tests/test_stats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@


from tale.base import Stats


class TestStats:

def test_replenish_hp(self):
stats = Stats()
stats.max_hp = 100
stats.hp = 0

stats.replenish_hp(10)

assert stats.hp == 10

stats.replenish_hp()

assert stats.hp == 100

def test_replenish_combat_points(self):
stats = Stats()
stats.max_combat_points = 100
stats.combat_points = 0

stats.replenish_combat_points(10)

assert stats.combat_points == 10

stats.replenish_combat_points()

assert stats.combat_points == 100

0 comments on commit 6c8a354

Please sign in to comment.