Skip to content

Commit b8b3c6b

Browse files
committed
feat(ai-npc): add personality trend system for npc interactions
implement personality trend mechanics that affect player reputation and relationships add personality type classification for npcs (vile/noble/normal) modify relationship calculations to consider player's personality trend update database schema and types to support new personality system
1 parent 0517cf6 commit b8b3c6b

5 files changed

Lines changed: 188 additions & 48 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE `game_archive` ADD COLUMN `personality_charm` INTEGER NOT NULL DEFAULT 0;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
Warnings:
3+
4+
- You are about to drop the column `personality_charm` on the `game_archive` table. All the data in the column will be lost.
5+
6+
*/
7+
-- AlterTable
8+
ALTER TABLE `game_archive` DROP COLUMN `personality_charm`,
9+
ADD COLUMN `personality_trend` INTEGER NOT NULL DEFAULT 0;

packages/backend/prisma/schema.prisma

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ model user {
3838

3939
//游戏档案 e.g. 约娜火法档、阿娜大剑档、阿娜大剑档2
4040
model game_archive {
41-
id Int @id @default(autoincrement())
42-
name String @db.VarChar(50) // 档案名称
43-
role_name String @db.VarChar(50) // 游玩角色
44-
user_id Int //逻辑外键,指向user表的id
41+
id Int @id @default(autoincrement())
42+
name String @db.VarChar(50) // 档案名称
43+
role_name String @db.VarChar(50) // 游玩角色
44+
personality_trend Int @default(0) // 人格倾向,-100 ~ +100(恶~善)
45+
46+
user_id Int //逻辑外键,指向user表的id
4547
4648
create_at DateTime? @default(now()) @db.Timestamp(0)
4749
update_at DateTime? @default(now()) @db.Timestamp(0)
@@ -64,8 +66,8 @@ model ai_npc {
6466

6567
// 与AI NPC的对话历史
6668
model ai_conversation {
67-
id Int @id @default(autoincrement())
68-
keyname String @unique @db.VarChar(100) // 对话唯一标识
69+
id Int @id @default(autoincrement())
70+
keyname String @unique @db.VarChar(100) // 对话唯一标识
6971
history Json? //ai(langchain)使用的聊天历史
7072
summary String? @db.Text // 对话摘要
7173

packages/backend/src/business/ai-npc/ai-npc.ts

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import {
66
npc_existence_meta_data,
77
NpcAIInput,
88
NpcAIOutput,
9+
NpcExistenceMetaData,
910
NpcName,
1011
NpcStaus,
12+
PersonalityType,
1113
RelationshipTier,
1214
TAINpc,
1315
TraitList,
@@ -25,6 +27,8 @@ class AINpc implements TAINpc {
2527
relationshipValue: number;
2628
relationship: RelationshipTier;
2729
specialRelationship: string[];
30+
personality_trend: number;
31+
metadata: NpcExistenceMetaData;
2832

2933
aiNpcService: AiNpcService;
3034

@@ -35,6 +39,8 @@ class AINpc implements TAINpc {
3539
relationshipValue: number,
3640
relationship: RelationshipTier,
3741
specialRelationship: string[],
42+
personality_trend: number,
43+
metadata: NpcExistenceMetaData,
3844
status: NpcStaus = NpcStaus.normal,
3945
traits: TraitList[] = []
4046
) {
@@ -46,6 +52,23 @@ class AINpc implements TAINpc {
4652
this.relationshipValue = relationshipValue;
4753
this.relationship = relationship;
4854
this.specialRelationship = specialRelationship;
55+
this.personality_trend = personality_trend;
56+
this.metadata = metadata;
57+
}
58+
59+
async saveNpcToDB() {
60+
// 将数据更新到数据库
61+
await this.aiNpcService.dbService.ai_npc.updateMany({
62+
where: {
63+
game_archive_id: this.game_archive_id,
64+
name: this.npcName
65+
},
66+
data: {
67+
relationshipValue: this.relationshipValue,
68+
relationshipTier: this.relationship,
69+
specialRelationship: JSON.stringify(this.specialRelationship)
70+
}
71+
});
4972
}
5073

5174
/**
@@ -65,7 +88,7 @@ class AINpc implements TAINpc {
6588

6689
/**
6790
* 好感度等级变化时,根据存在感应用到玩家的声望、金币、经验值。
68-
* 数值 = (当前好感度 * npc该值的存在感数值) / 100,向下取整
91+
* 数值 = (好感度变化值 * npc该值的存在感数值) / 100,向下取整
6992
*
7093
*/
7194
async applyRelationshipChangeToPlayer(relationshipChange: number) {
@@ -75,9 +98,9 @@ class AINpc implements TAINpc {
7598
}
7699

77100
// 数值 = (好感度变化值 * npc该值的存在感数值) / 100,向下取整
78-
const wealthChange = Math.floor((relationshipChange * metaData.wealth) / 100);
79-
const influenceChange = Math.floor((relationshipChange * metaData.influence) / 100);
80-
const expChange = Math.floor((relationshipChange * metaData.exp) / 100);
101+
const wealthChange = Math.floor((relationshipChange * metaData.wealth * 4) / 100);
102+
const influenceChange = Math.floor((relationshipChange * metaData.influence * 5) / 100);
103+
const expChange = Math.floor((relationshipChange * metaData.exp * 10) / 100);
81104

82105
const game_actions: GameAction[] = [];
83106

@@ -88,12 +111,12 @@ class AINpc implements TAINpc {
88111
msg: `${this.npcName}被你打动,资助了你${wealthChange}冠。\n`
89112
});
90113
}
91-
114+
// 人格倾向应用于变化
92115
if (influenceChange !== 0) {
93116
game_actions.push({
94117
code: ActionCode.ChangeReputation,
95-
cnt: influenceChange,
96-
msg: `声望 ${influenceChange > 0 ? `你获得了${this.npcName}的认可,声望+了${influenceChange}。\n` : `你不受${this.npcName}待见,声望-了${-influenceChange}。\n`}`
118+
cnt: influenceChange > 0 ? influenceChange + this.personality_trend : 0,
119+
msg: `${influenceChange > 0 ? `这获得了认可,${this.personality_trend > 0 ? '蒸蒸日上啊,' : ''}当地声望+${influenceChange}。\n` : `这不受待见,${this.personality_trend > 0 ? '' : '去他的吧,'}当地声望-${-influenceChange}。\n`}`
97120
});
98121
}
99122

@@ -108,6 +131,44 @@ class AINpc implements TAINpc {
108131
return game_actions;
109132
}
110133

134+
/**
135+
* 好感度变化时,应用到玩家角色的人格倾向
136+
*/
137+
async applyRelationshipChangeToPlayerPersonalityTrend(
138+
relationshipChange: number,
139+
mod_action_msg: string
140+
) {
141+
if (
142+
relationshipChange === 0 ||
143+
this.metadata.personality_type === PersonalityType.normal ||
144+
this.metadata.personality_trend === 0
145+
) {
146+
return mod_action_msg;
147+
} else {
148+
// 更新玩家角色的人格倾向
149+
let change =
150+
(relationshipChange *
151+
this.metadata.personality_trend *
152+
(this.metadata.personality_type === PersonalityType.vile ? -1 : 1)) /
153+
100;
154+
change = change > 0 ? Math.min(change, 3) : Math.max(change, -3);
155+
this.personality_trend = this.personality_trend + change;
156+
157+
await this.aiNpcService.dbService.game_archive.updateMany({
158+
where: {
159+
id: this.game_archive_id
160+
},
161+
data: {
162+
personality_trend: this.personality_trend
163+
}
164+
});
165+
166+
// mod_action_msg += `人格倾向 ${change > 0 ? '+' : '-'} ${Math.abs(change)}(${this.personality_trend})\n`;
167+
mod_action_msg += `${change > 0 ? `与${this.npcName}这样的人亲近了\n` : `与${this.npcName}这样的人疏远了\n`}`;
168+
return mod_action_msg;
169+
}
170+
}
171+
111172
/**
112173
* 将ai返回的操作应用到数据库,并转为返回给游戏程序的格式
113174
*/
@@ -128,7 +189,23 @@ class AINpc implements TAINpc {
128189
// 使得绝对值越高的好感度变化幅度越小
129190
// 阻尼系数:(150 - |当前好感度|) / 150。当好感度为0时系数为1,为100时系数为0.33
130191
const dampingFactor = Math.max(0.2, (150 - Math.abs(this.relationshipValue)) / 150);
131-
const change = Math.ceil(rawChange * dampingFactor);
192+
let change = Math.max(Math.ceil(rawChange * dampingFactor), 5);
193+
194+
// 人格魅力影响:负值容易与小人交好,正值容易与普通人、君子交好(物以类聚人以群分)
195+
if (this.metadata.personality_type === PersonalityType.vile && change !== 0) {
196+
if (this.personality_trend < 0) {
197+
change = change + 1;
198+
} else {
199+
change = change - 1;
200+
}
201+
}
202+
if (this.metadata.personality_type === PersonalityType.noble && change !== 0) {
203+
if (this.personality_trend >= 0) {
204+
change = change + 1;
205+
} else {
206+
change = change - 1;
207+
}
208+
}
132209

133210
this.relationshipValue += change;
134211
relationshipChange += change;
@@ -149,7 +226,7 @@ class AINpc implements TAINpc {
149226
this.relationship = RelationshipTier.hostile;
150227
}
151228

152-
mod_action_msg += `好感度变为${this.relationshipValue}${this.relationship})\n`;
229+
mod_action_msg += `好感度${change > 0 ? '+' : '-'} ${Math.abs(change)}${this.relationshipValue}${this.relationship})\n`;
153230
}
154231
break;
155232
case ActionCode.addSpecialRelationship:
@@ -181,17 +258,7 @@ class AINpc implements TAINpc {
181258
}
182259

183260
// 将数据更新到数据库
184-
await this.aiNpcService.dbService.ai_npc.updateMany({
185-
where: {
186-
game_archive_id: this.game_archive_id,
187-
name: this.npcName
188-
},
189-
data: {
190-
relationshipValue: this.relationshipValue,
191-
relationshipTier: this.relationship,
192-
specialRelationship: JSON.stringify(this.specialRelationship)
193-
}
194-
});
261+
await this.saveNpcToDB();
195262
}
196263

197264
// 应用好感度变化带来的额外影响
@@ -200,6 +267,14 @@ class AINpc implements TAINpc {
200267
game_action.push(...game_actions);
201268
}
202269

270+
// 应用好感度变化到玩家角色人格魅力
271+
if (relationshipChange !== 0) {
272+
mod_action_msg = await this.applyRelationshipChangeToPlayerPersonalityTrend(
273+
relationshipChange,
274+
mod_action_msg
275+
);
276+
}
277+
203278
// 返回回复和需要在游戏程序中进行的数据操作
204279
return {
205280
msg: aiOutput.reply,

0 commit comments

Comments
 (0)