mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 12:56:30 +01:00
parent
387533d1f0
commit
c8d75665d2
3 changed files with 24 additions and 51 deletions
|
|
@ -20,6 +20,7 @@
|
|||
a reload (regression).
|
||||
- [Docs] Added new [Server-Lifecycle][doc-server-lifecycle] page to describe
|
||||
the hooks called on server start/stop/reload (Griatch)
|
||||
- [Docs] Doc typo fixes (Griatch, chiizujin)
|
||||
|
||||
[pull3438]: https://github.com/evennia/evennia/pull/3446
|
||||
[pull3485]: https://github.com/evennia/evennia/pull/3485
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
# Player Characters
|
||||
|
||||
In the [previous lesson about rules and dice rolling](./Beginner-Tutorial-Rules.md) we made some
|
||||
assumptions about the "Player Character" entity:
|
||||
In the [previous lesson about rules and dice rolling](./Beginner-Tutorial-Rules.md) we made some assumptions about the "Player Character" entity:
|
||||
|
||||
- It should store Abilities on itself as `character.strength`, `character.constitution` etc.
|
||||
- It should have a `.heal(amount)` method.
|
||||
|
||||
So we have some guidelines of how it should look! A Character is a database entity with values that
|
||||
should be able to be changed over time. It makes sense to base it off Evennia's
|
||||
So we have some guidelines of how it should look! A Character is a database entity with values that should be able to be changed over time. It makes sense to base it off Evennia's
|
||||
[DefaultCharacter Typeclass](../../../Components/Typeclasses.md). The Character class is like a 'character sheet' in a tabletop
|
||||
RPG, it will hold everything relevant to that PC.
|
||||
|
||||
|
|
@ -16,8 +14,7 @@ RPG, it will hold everything relevant to that PC.
|
|||
Player Characters (PCs) are not the only "living" things in our world. We also have _NPCs_
|
||||
(like shopkeepers and other friendlies) as well as _monsters_ (mobs) that can attack us.
|
||||
|
||||
In code, there are a few ways we could structure this. If NPCs/monsters were just special cases of PCs,
|
||||
we could use a class inheritance like this:
|
||||
In code, there are a few ways we could structure this. If NPCs/monsters were just special cases of PCs, we could use a class inheritance like this:
|
||||
|
||||
```python
|
||||
from evennia import DefaultCharacter
|
||||
|
|
@ -34,9 +31,7 @@ class EvAdventureMob(EvAdventureNPC):
|
|||
|
||||
All code we put on the `Character` class would now be inherited to `NPC` and `Mob` automatically.
|
||||
|
||||
However, in _Knave_, NPCs and particularly monsters are _not_ using the same rules as PCs - they are
|
||||
simplified to use a Hit-Die (HD) concept. So while still character-like, NPCs should be separate from
|
||||
PCs like this:
|
||||
However, in _Knave_, NPCs and particularly monsters are _not_ using the same rules as PCs - they are simplified to use a Hit-Die (HD) concept. So while still character-like, NPCs should be separate from PCs like this:
|
||||
|
||||
```python
|
||||
from evennia import DefaultCharacter
|
||||
|
|
@ -60,8 +55,7 @@ Nevertheless, there are some things that _should_ be common for all 'living thin
|
|||
- All can loot their fallen foes.
|
||||
- All can get looted when defeated.
|
||||
|
||||
We don't want to code this separately for every class but we no longer have a common parent
|
||||
class to put it on. So instead we'll use the concept of a _mixin_ class:
|
||||
We don't want to code this separately for every class but we no longer have a common parent class to put it on. So instead we'll use the concept of a _mixin_ class:
|
||||
|
||||
```python
|
||||
from evennia import DefaultCharacter
|
||||
|
|
@ -83,10 +77,7 @@ class EvAdventureMob(LivingMixin, EvadventureNPC):
|
|||
In [evennia/contrib/tutorials/evadventure/characters.py](../../../api/evennia.contrib.tutorials.evadventure.characters.md)
|
||||
is an example of a character class structure.
|
||||
```
|
||||
Above, the `LivingMixin` class cannot work on its own - it just 'patches' the other classes with some
|
||||
extra functionality all living things should be able to do. This is an example of
|
||||
_multiple inheritance_. It's useful to know about, but one should not over-do multiple inheritance
|
||||
since it can also get confusing to follow the code.
|
||||
Above, the `LivingMixin` class cannot work on its own - it just 'patches' the other classes with some extra functionality all living things should be able to do. This is an example of _multiple inheritance_. It's useful to know about, but one should not over-do multiple inheritance since it can also get confusing to follow the code.
|
||||
|
||||
## Living mixin class
|
||||
|
||||
|
|
@ -178,7 +169,6 @@ Most of these are empty since they will behave differently for characters and np
|
|||
|
||||
Once we create more of our game, we will need to remember to actually call these hook methods so they serve a purpose. For example, once we implement combat, we must remember to call `at_attacked` as well as the other methods involving taking damage, getting defeated or dying.
|
||||
|
||||
|
||||
## Character class
|
||||
|
||||
We will now start making the basic Character class, based on what we need from _Knave_.
|
||||
|
|
@ -234,8 +224,7 @@ class EvAdventureCharacter(LivingMixin, DefaultCharacter):
|
|||
|
||||
We make an assumption about our rooms here - that they have a property `.allow_death`. We need to make a note to actually add such a property to rooms later!
|
||||
|
||||
In our `Character` class we implement all attributes we want to simulate from the _Knave_ ruleset.
|
||||
The `AttributeProperty` is one way to add an Attribute in a field-like way; these will be accessible on every character in several ways:
|
||||
In our `Character` class we implement all attributes we want to simulate from the _Knave_ ruleset. The `AttributeProperty` is one way to add an Attribute in a field-like way; these will be accessible on every character in several ways:
|
||||
|
||||
- As `character.strength`
|
||||
- As `character.db.strength`
|
||||
|
|
@ -249,7 +238,7 @@ We implement the Player Character versions of `at_defeat` and `at_death`. We als
|
|||
|
||||
### Funcparser inlines
|
||||
|
||||
This piece of code is worth some more explanation:
|
||||
This piece of code in the `at_defeat` method above is worth some more extra explanation:
|
||||
|
||||
```python
|
||||
self.location.msg_contents(
|
||||
|
|
@ -259,8 +248,7 @@ self.location.msg_contents(
|
|||
|
||||
Remember that `self` is the Character instance here. So `self.location.msg_contents` means "send a message to everything inside my current location". In other words, send a message to everyone in the same place as the character.
|
||||
|
||||
The `$You() $conj(collapse)` are [FuncParser inlines](../../../Components/FuncParser.md). These are functions that
|
||||
execute in the string. The resulting string may look different for different audiences. The `$You()` inline function will use `from_obj` to figure out who 'you' are and either show your name or 'You'. The `$conj()` (verb conjugator) will tweak the (English) verb to match.
|
||||
The `$You() $conj(collapse)` are [FuncParser inlines](../../../Components/FuncParser.md). These are functions that execute in the string. The resulting string may look different for different audiences. The `$You()` inline function will use `from_obj` to figure out who 'you' are and either show your name or 'You'. The `$conj()` (verb conjugator) will tweak the (English) verb to match.
|
||||
|
||||
- You will see: `"You collapse in a heap, alive but beaten."`
|
||||
- Others in the room will see: `"Thomas collapses in a heap, alive but beaten."`
|
||||
|
|
@ -303,10 +291,7 @@ You can easily make yourself an `EvAdventureCharacter` in-game by using the
|
|||
|
||||
You can now do `examine self` to check your type updated.
|
||||
|
||||
If you want _all_ new Characters to be of this type you need to tell Evennia about it. Evennia
|
||||
uses a global setting `BASE_CHARACTER_TYPECLASS` to know which typeclass to use when creating
|
||||
Characters (when logging in, for example). This defaults to `typeclasses.characters.Character` (that is,
|
||||
the `Character` class in `mygame/typeclasses/characters.py`).
|
||||
If you want _all_ new Characters to be of this type you need to tell Evennia about it. Evennia uses a global setting `BASE_CHARACTER_TYPECLASS` to know which typeclass to use when creating Characters (when logging in, for example). This defaults to `typeclasses.characters.Character` (that is, the `Character` class in `mygame/typeclasses/characters.py`).
|
||||
|
||||
There are thus two ways to weave your new Character class into Evennia:
|
||||
|
||||
|
|
@ -327,8 +312,7 @@ instead.
|
|||
|
||||
> Create a new module `mygame/evadventure/tests/test_characters.py`
|
||||
|
||||
For testing, we just need to create a new EvAdventure character and check
|
||||
that calling the methods on it doesn't error out.
|
||||
For testing, we just need to create a new EvAdventure character and check that calling the methods on it doesn't error out.
|
||||
|
||||
```python
|
||||
# mygame/evadventure/tests/test_characters.py
|
||||
|
|
@ -368,22 +352,18 @@ class TestCharacters(BaseEvenniaTest):
|
|||
# tests for other methods ...
|
||||
|
||||
```
|
||||
If you followed the previous lessons, these tests should look familiar. Consider adding
|
||||
tests for other methods as practice. Refer to previous lessons for details.
|
||||
If you followed the previous lessons, these tests should look familiar. Consider adding tests for other methods as practice. Refer to previous lessons for details.
|
||||
|
||||
For running the tests you do:
|
||||
|
||||
evennia test --settings settings.py .evadventure.tests.test_character
|
||||
evennia test --settings settings.py .evadventure.tests.test_characters
|
||||
|
||||
|
||||
## About races and classes
|
||||
|
||||
_Knave_ doesn't have any D&D-style _classes_ (like Thief, Fighter etc). It also does not bother with
|
||||
_races_ (like dwarves, elves etc). This makes the tutorial shorter, but you may ask yourself how you'd
|
||||
add these functions.
|
||||
_Knave_ doesn't have any D&D-style _classes_ (like Thief, Fighter etc). It also does not bother with _races_ (like dwarves, elves etc). This makes the tutorial shorter, but you may ask yourself how you'd add these functions.
|
||||
|
||||
In the framework we have sketched out for _Knave_, it would be simple - you'd add your race/class as
|
||||
an Attribute on your Character:
|
||||
In the framework we have sketched out for _Knave_, it would be simple - you'd add your race/class as an Attribute on your Character:
|
||||
|
||||
```python
|
||||
# mygame/evadventure/characters.py
|
||||
|
|
@ -399,8 +379,7 @@ class EvAdventureCharacter(LivingMixin, DefaultCharacter):
|
|||
charrace = AttributeProperty("Human")
|
||||
|
||||
```
|
||||
We use `charclass` rather than `class` here, because `class` is a reserved Python keyword. Naming
|
||||
`race` as `charrace` thus matches in style.
|
||||
We use `charclass` rather than `class` here, because `class` is a reserved Python keyword. Naming `race` as `charrace` thus matches in style.
|
||||
|
||||
We'd then need to expand our [rules module](./Beginner-Tutorial-Rules.md) (and later
|
||||
[character generation](./Beginner-Tutorial-Chargen.md) to check and include what these classes mean.
|
||||
|
|
@ -409,23 +388,16 @@ We'd then need to expand our [rules module](./Beginner-Tutorial-Rules.md) (and l
|
|||
## Summary
|
||||
|
||||
|
||||
With the `EvAdventureCharacter` class in place, we have a better understanding of how our PCs will look
|
||||
like under _Knave_.
|
||||
With the `EvAdventureCharacter` class in place, we have a better understanding of how our PCs will look like under _Knave_.
|
||||
|
||||
For now, we only have bits and pieces and haven't been testing this code in-game. But if you want
|
||||
you can swap yourself into `EvAdventureCharacter` right now. Log into your game and run
|
||||
the command
|
||||
For now, we only have bits and pieces and haven't been testing this code in-game. But if you want you can swap yourself into `EvAdventureCharacter` right now. Log into your game and run the command
|
||||
|
||||
type self = evadventure.characters.EvAdventureCharacter
|
||||
|
||||
If all went well, `ex self` will now show your typeclass as being `EvAdventureCharacter`.
|
||||
Check out your strength with
|
||||
If all went well, `ex self` will now show your typeclass as being `EvAdventureCharacter`. Check out your strength with
|
||||
|
||||
py self.strength = 3
|
||||
|
||||
```{important}
|
||||
When doing `ex self` you will _not_ see all your Abilities listed yet. That's because
|
||||
Attributes added with `AttributeProperty` are not available until they have been accessed at
|
||||
least once. So once you set (or look at) `.strength` above, `strength` will show in `examine` from
|
||||
then on.
|
||||
When doing `ex self` you will _not_ see all your Abilities listed yet. That's because Attributes added with `AttributeProperty` are not available until they have been accessed at least once. So once you set (or look at) `.strength` above, `strength` will show in `examine` from then on.
|
||||
```
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ class EvAdventureObject(DefaultObject):
|
|||
"""The top of the description"""
|
||||
return ""
|
||||
|
||||
def get_display_desc(self, looker, **kwargs)
|
||||
def get_display_desc(self, looker, **kwargs):
|
||||
"""The main display - show object stats"""
|
||||
return get_obj_stats(self, owner=looker)
|
||||
|
||||
|
|
@ -216,7 +216,7 @@ class EvAdventureConsumable(EvAdventureObject):
|
|||
"""Called when using the item"""
|
||||
pass
|
||||
|
||||
def at_post_use(self. user, *args, **kwargs):
|
||||
def at_post_use(self, user, *args, **kwargs):
|
||||
"""Called after using the item"""
|
||||
# detract a usage, deleting the item if used up.
|
||||
self.uses -= 1
|
||||
|
|
@ -452,7 +452,7 @@ _BARE_HANDS = None
|
|||
|
||||
# ...
|
||||
|
||||
class WeaponBareHands(EvAdventureWeapon)
|
||||
class WeaponBareHands(EvAdventureWeapon):
|
||||
obj_type = ObjType.WEAPON
|
||||
inventory_use_slot = WieldLocation.WEAPON_HAND
|
||||
attack_type = Ability.STR
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue