1
0

Add player leveling

This commit is contained in:
Timothy Warren 2022-01-25 15:51:59 -05:00
parent 6462fe06ac
commit c98ccc168c
5 changed files with 154 additions and 0 deletions

View File

@ -46,6 +46,8 @@ class Fighter(BaseComponent):
self.engine.message_log.add_message(death_message, death_message_color)
self.engine.player.level.add_xp(self.parent.level.xp_given)
def heal(self, amount: int) -> int:
if self.hp == self.max_hp:
return 0

74
components/level.py Normal file
View File

@ -0,0 +1,74 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from components.base_component import BaseComponent
if TYPE_CHECKING:
from entity import Actor
class Level(BaseComponent):
parent: Actor
def __init__(
self,
current_level: int = 1,
current_xp: int = 0,
level_up_base: int = 0,
level_up_factor: int = 150,
xp_given: int = 0
):
self.current_level = current_level
self.current_xp = current_xp
self.level_up_base = level_up_base
self.level_up_factor = level_up_factor
self.xp_given = xp_given
@property
def experience_to_next_level(self) -> int:
return self.level_up_base + self.current_level * self.level_up_factor
@property
def requires_level_up(self) -> bool:
return self.current_xp > self.experience_to_next_level
def add_xp(self, xp: int) -> None:
if xp == 0 or self.level_up_base == 0:
return
self.current_xp += xp
self.engine.message_log.add_message(f"You gain {xp} experience points.")
if self.requires_level_up:
self.engine.message_log.add_message(
f"You advance to level {self.current_level + 1}!"
)
def increase_level(self) -> None:
self.current_xp -= self.experience_to_next_level
self.current_level += 1
def increase_max_hp(self, amount: int = 20) -> None:
self.parent.fighter.max_hp += amount
self.parent.fighter.hp += amount
self.engine.message_log.add_message("Your health improves!")
self.increase_level()
def increase_power(self, amount: int = 1) -> None:
self.parent.fighter.power += amount
self.engine.message_log.add_message("You feel stronger!")
self.increase_level()
def increase_defense(self, amount: int = 1) -> None:
self.parent.fighter.defense += amount
self.engine.message_log.add_message("Your movements are getting swifter!")
self.increase_level()

View File

@ -11,6 +11,7 @@ if TYPE_CHECKING:
from components.consumable import Consumable
from components.fighter import Fighter
from components.inventory import Inventory
from components.level import Level
from game_map import GameMap
T = TypeVar("T", bound="Entity")
@ -95,6 +96,7 @@ class Actor(Entity):
ai_cls: Type[BaseAI],
fighter: Fighter,
inventory: Inventory,
level: Level
):
super().__init__(
x=x,
@ -114,6 +116,9 @@ class Actor(Entity):
self.inventory = inventory
self.inventory.parent = self
self.level = level
self.level.parent = self
@property
def is_alive(self) -> bool:
"""Returns True as long as this actor can perform actions."""

View File

@ -2,6 +2,7 @@ from components.ai import HostileEnemy
from components import consumable
from components.fighter import Fighter
from components.inventory import Inventory
from components.level import Level
from entity import Actor, Item
player = Actor(
@ -11,6 +12,7 @@ player = Actor(
ai_cls=HostileEnemy,
fighter=Fighter(hp=30, defense=2, power=5),
inventory=Inventory(capacity=26),
level=Level(level_up_base=200),
)
orc = Actor(
@ -20,6 +22,7 @@ orc = Actor(
ai_cls=HostileEnemy,
fighter=Fighter(hp=10, defense=0, power=3),
inventory=Inventory(capacity=0),
level=Level(xp_given=35),
)
troll = Actor(
char="T",
@ -28,6 +31,7 @@ troll = Actor(
ai_cls=HostileEnemy,
fighter=Fighter(hp=16, defense=1, power=4),
inventory=Inventory(capacity=0),
level=Level(xp_given=100),
)
confusion_scroll = Item(

View File

@ -132,6 +132,8 @@ class EventHandler(BaseEventHandler):
if not self.engine.player.is_alive:
# The player was killed sometime during or after the action.
return GameOverEventHandler(self.engine)
elif self.engine.player.level.requires_level_up:
return LevelUpEventHandler(self.engine)
return MainGameEventHandler(self.engine) # Return to the main handler.
return self
@ -193,6 +195,73 @@ class AskUserEventHandler(EventHandler):
return MainGameEventHandler(self.engine)
class LevelUpEventHandler(AskUserEventHandler):
TITLE = "Level Up"
def on_render(self, console: tcod.Console) -> None:
super().on_render(console)
if self.engine.player.x <= 30:
x = 40
else:
x = 0
console.draw_frame(
x=x,
y=0,
width=35,
height=8,
title=self.TITLE,
clear=True,
fg=(255, 255, 255),
bg=(0, 0, 0)
)
console.print(x + 1, 1, "Congratulations! You level up!")
console.print(x + 1, 2, "Select an attribut to increase.")
console.print(
x=x + 1,
y=4,
string=f"a) Constitution (+20 HP, from {self.engine.player.fighter.max_hp})"
)
console.print(
x=x + 1,
y=5,
string=f"b) Strength (+1 attack, from {self.engine.player.fighter.power})"
)
console.print(
x=x + 1,
y=6,
string=f"c) Agility (+1 defense, from {self.engine.player.fighter.defense})"
)
def ev_keydown(self, event: tcod.event.KeyDown) -> Optional[ActionOrHandler]:
player = self.engine.player
key = event.sym
index = key - tcod.event.K_a
if 0 <= index <= 2:
if index == 0:
player.level.increase_max_hp()
elif index == 1:
player.level.increase_power()
else:
player.level.increase_defense()
else:
self.engine.message_log.add_message("Invalid entry.", color.invalid)
return None
return super().ev_keydown(event)
def ev_mousebuttondown(self, event: tcod.event.MouseButtonDown) -> Optional[ActionOrHandler]:
"""
Don't allow the player to click to exit the menu, like normal
"""
return None
class InventoryEventHandler(AskUserEventHandler):
"""This handler lets the user select an item.