8. 非玩家角色¶
非玩家角色,或 NPCs,是所有不受玩家控制的活躍代理的通用術語。 NPCs 可以是任何東西,從商人和任務提供者,到怪物和老闆。 他們也可以是「風味」角色,例如做家務的城鎮居民、耕作的農夫,讓世界感覺「更有活力」。
在本課中,我們將基於 Knave 規則集建立 EvAdventure NPCs 的基底類別。根據_Knave_規則,與我們之前設計的PC字元相比,NPCs有一些簡化的統計資料。
8.1. NPC基類¶
建立一個新模組
evadventure/npcs.py。
1# in evadventure/npcs.py
2
3from evennia import DefaultCharacter, AttributeProperty
4
5from .characters import LivingMixin
6from .enums import Ability
7from .objects import get_bare_hands
8
9class EvAdventureNPC(LivingMixin, DefaultCharacter):
10 """Base class for NPCs"""
11
12 is_pc = False
13 hit_dice = AttributeProperty(default=1, autocreate=False)
14 armor = AttributeProperty(default=1, autocreate=False) # +10 to get armor defense
15 hp_multiplier = AttributeProperty(default=4, autocreate=False) # 4 default in Knave
16 hp = AttributeProperty(default=None, autocreate=False) # internal tracking, use .hp property
17 morale = AttributeProperty(default=9, autocreate=False)
18 allegiance = AttributeProperty(default=Ability.ALLEGIANCE_HOSTILE, autocreate=False)
19
20 weapon = AttributeProperty(default=get_bare_hands, autocreate=False) # instead of inventory
21 coins = AttributeProperty(default=1, autocreate=False) # coin loot
22
23 is_idle = AttributeProperty(default=False, autocreate=False)
24
25 @property
26 def strength(self):
27 return self.hit_dice
28
29 @property
30 def dexterity(self):
31 return self.hit_dice
32
33 @property
34 def constitution(self):
35 return self.hit_dice
36
37 @property
38 def intelligence(self):
39 return self.hit_dice
40
41 @property
42 def wisdom(self):
43 return self.hit_dice
44
45 @property
46 def charisma(self):
47 return self.hit_dice
48
49 @property
50 def hp_max(self):
51 return self.hit_dice * self.hp_multiplier
52
53 def at_object_creation(self):
54 """
55 Start with max health.
56
57 """
58 self.hp = self.hp_max
59 self.tags.add("npcs", category="group")
60
61
62class EvAdventureMob(EvAdventureNPC):
63 """
64 Mob(ile) NPC to be used for enemies.
65
66 """
第 9 行:透過使用_多重繼承_,我們使用我們在角色課程中建立的
LinvingMixin。這包括許多有用的方法,例如顯示我們的「傷害等級」、用於治療的方法、受到攻擊、傷害時呼叫的鉤子等等。我們可以在即將到來的 NPC 子類別中重複使用所有這些。第 12 行:
is_pc是一種快速便捷的方法來檢查這是否是 PC。我們將在接下來的戰鬥基礎課程中使用它。第 13 行:NPC 被簡化,因為所有統計資料僅基於
Hit dice數字(請參閱 第 25-51 行)。我們將armor和weapon作為直接屬性 儲存在班級上,而不是費心實現完整的裝備系統。第 17、18 行:
morale和allegiance是 Knave 屬性,決定 NPC 在戰鬥情況下逃跑的可能性以及他們是敵對還是友好。第 19 行:
is_idleAttribute 是一個有用的屬性。它應該在所有 NPCs 上可用,並將用於完全停用 AI。第 59 行:我們確保 tag NPCs。我們可能希望稍後將不同的 NPCs 分組在一起,例如,如果其中一個受到攻擊,則讓所有具有相同 tag 的 NPCs 做出回應。
我們建立一個空子類別EvAdventureMob。 「暴民」(「移動」的縮寫)是一個常見的 MUD 術語,表示可以自行移動的 NPCs。我們將來將使用這個類別來代表遊戲中的敵人。我們將回到這堂課[在關於新增AI的課程中][Beginner-Tutoroal-AI]。
8.2. 測試¶
建立一個新模組
evadventure/tests/test_npcs.py
還沒有太多需要測試的內容,但我們將來將使用相同的模組來測試 NPCs 的其他方面,所以讓我們現在建立它。
# in evadventure/tests/test_npcs.py
from evennia import create_object
from evennia.utils.test_resources import EvenniaTest
from .. import npcs
class TestNPCBase(EvenniaTest):
"""Test the NPC base class"""
def test_npc_base(self):
npc = create_object(
npcs.EvAdventureNPC,
key="TestNPC",
attributes=[("hit_dice", 4)], # set hit_dice to 4
)
self.assertEqual(npc.hp_multiplier, 4)
self.assertEqual(npc.hp, 16)
self.assertEqual(npc.strength, 4)
self.assertEqual(npc.charisma, 4)
這裡沒什麼特別的。請注意 create_object 輔助函式如何將 attributes 作為關鍵字。這是一個元組列表,我們用來為屬性設定與預設值不同的值。然後我們檢查一些屬性以確保它們傳回我們期望的結果。
8.3. 結論¶
在_Knave_中,NPC是玩家角色的簡化版本。在其他遊戲和規則系統中,它們可能幾乎完全相同。
NPC 類別就位後,我們就足以建立一個「測試虛擬物件」。由於它還沒有AI,所以它不會反擊,但當我們在接下來的課程中測試我們的戰鬥時,有東西可以擊中就足夠了。