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.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: def heal(self, amount: int) -> int:
if self.hp == self.max_hp: if self.hp == self.max_hp:
return 0 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.consumable import Consumable
from components.fighter import Fighter from components.fighter import Fighter
from components.inventory import Inventory from components.inventory import Inventory
from components.level import Level
from game_map import GameMap from game_map import GameMap
T = TypeVar("T", bound="Entity") T = TypeVar("T", bound="Entity")
@ -95,6 +96,7 @@ class Actor(Entity):
ai_cls: Type[BaseAI], ai_cls: Type[BaseAI],
fighter: Fighter, fighter: Fighter,
inventory: Inventory, inventory: Inventory,
level: Level
): ):
super().__init__( super().__init__(
x=x, x=x,
@ -114,6 +116,9 @@ class Actor(Entity):
self.inventory = inventory self.inventory = inventory
self.inventory.parent = self self.inventory.parent = self
self.level = level
self.level.parent = self
@property @property
def is_alive(self) -> bool: def is_alive(self) -> bool:
"""Returns True as long as this actor can perform actions.""" """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 import consumable
from components.fighter import Fighter from components.fighter import Fighter
from components.inventory import Inventory from components.inventory import Inventory
from components.level import Level
from entity import Actor, Item from entity import Actor, Item
player = Actor( player = Actor(
@ -11,6 +12,7 @@ player = Actor(
ai_cls=HostileEnemy, ai_cls=HostileEnemy,
fighter=Fighter(hp=30, defense=2, power=5), fighter=Fighter(hp=30, defense=2, power=5),
inventory=Inventory(capacity=26), inventory=Inventory(capacity=26),
level=Level(level_up_base=200),
) )
orc = Actor( orc = Actor(
@ -20,6 +22,7 @@ orc = Actor(
ai_cls=HostileEnemy, ai_cls=HostileEnemy,
fighter=Fighter(hp=10, defense=0, power=3), fighter=Fighter(hp=10, defense=0, power=3),
inventory=Inventory(capacity=0), inventory=Inventory(capacity=0),
level=Level(xp_given=35),
) )
troll = Actor( troll = Actor(
char="T", char="T",
@ -28,6 +31,7 @@ troll = Actor(
ai_cls=HostileEnemy, ai_cls=HostileEnemy,
fighter=Fighter(hp=16, defense=1, power=4), fighter=Fighter(hp=16, defense=1, power=4),
inventory=Inventory(capacity=0), inventory=Inventory(capacity=0),
level=Level(xp_given=100),
) )
confusion_scroll = Item( confusion_scroll = Item(

View File

@ -132,6 +132,8 @@ class EventHandler(BaseEventHandler):
if not self.engine.player.is_alive: if not self.engine.player.is_alive:
# The player was killed sometime during or after the action. # The player was killed sometime during or after the action.
return GameOverEventHandler(self.engine) 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 MainGameEventHandler(self.engine) # Return to the main handler.
return self return self
@ -193,6 +195,73 @@ class AskUserEventHandler(EventHandler):
return MainGameEventHandler(self.engine) 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): class InventoryEventHandler(AskUserEventHandler):
"""This handler lets the user select an item. """This handler lets the user select an item.