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.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
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.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."""
|
||||||
|
@ -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(
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user