Add player leveling
This commit is contained in:
parent
6462fe06ac
commit
c98ccc168c
@ -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
74
components/level.py
Normal 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()
|
@ -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."""
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user