15.3 Affection System Design
15.3.1 Affection Level Classification
In Cyber Town, NPC attitudes towards players change with interactions. We designed a five-level affection system, from stranger to close friend, with each level having different score ranges and corresponding behavioral performances.
The core idea of the affection system is: by quantifying the relationship between NPCs and players, make NPC replies more realistic and layered. When players first enter the game, all NPCs have a stranger attitude towards players, with replies being polite but distant. As conversations progress, if players behave friendly, NPC affection will gradually increase, and replies will become more cordial and detailed.
We divide affection into five levels, each corresponding to a score range, as shown in Figure 15.8:

Figure 15.8 Affection Level Classification
Stranger (0-20 points): NPC just met the player, attitude is polite but maintains distance. Replies are brief, won't actively share personal information.
Familiar (21-40 points): NPC starts to remember the player, willing to have simple exchanges. Replies become more natural, occasionally sharing some work-related information.
Friendly (41-60 points): NPC treats the player as a friend, willing to share more information. Replies are more detailed, will actively ask about the player's situation.
Intimate (61-80 points): NPC trusts the player very much, willing to share private topics. Replies are full of enthusiasm, will provide help and advice to the player.
Close Friend (81-100 points): NPC treats the player as the best friend, talks about everything. Replies are very cordial, will share inner thoughts and feelings.
This design allows players to clearly feel the change in their relationship with NPCs, and also provides a foundation for subsequent gameplay. For example, only after reaching a certain affection level will NPCs share certain special information or provide special tasks.
15.3.2 Affection Calculation Logic
Affection calculation needs to consider multiple factors. We can't simply add a fixed score for each conversation, which would make the system appear mechanical and unrealistic. A good affection system should be able to identify the player's attitude and dynamically adjust scores based on conversation content.
In Cyber Town, we use LLM to analyze conversation content, judging whether the player's attitude is friendly, neutral, or unfriendly. Then we adjust the affection score based on the judgment result. This process is automatic, players don't need to deliberately choose options, making interactions more natural.
The affection calculation process is shown in Figure 15.9:

Figure 15.9 Affection Calculation Process
class RelationshipManager:
"""Affection manager"""
def __init__(self):
self.affinity_data = {} # Store affection data
self.llm = HelloAgentsLLM() # For analyzing conversations
def analyze_sentiment(self, player_message: str, npc_reply: str) -> int:
"""Analyze conversation sentiment, return affection change value"""
prompt = f"""Analyze the player's attitude in the following conversation:
Player: {player_message}
NPC: {npc_reply}
Please judge if the player's attitude is:
1. Friendly (+5 points): Polite, enthusiastic, expressing thanks or agreement
2. Neutral (+2 points): Normal inquiry or statement
3. Unfriendly (-3 points): Rude, indifferent, critical or negative
Only return the number, no other content."""
response = self.llm.think([{"role": "user", "content": prompt}])
try:
score_change = int(response.strip())
return max(-3, min(5, score_change)) # Limit between -3 and 5
except:
return 2 # Default neutral
def update_affinity(self, npc_id: str, player_name: str,
player_message: str, npc_reply: str) -> dict:
"""Update affection"""
key = f"{npc_id}_{player_name}"
# Get current affection
if key not in self.affinity_data:
self.affinity_data[key] = {
"score": 0,
"level": "Stranger",
"interaction_count": 0
}
# Analyze conversation sentiment
score_change = self.analyze_sentiment(player_message, npc_reply)
# Update score
current_score = self.affinity_data[key]["score"]
new_score = max(0, min(100, current_score + score_change))
# Update level
level = self.get_affinity_level(new_score)
# Update data
self.affinity_data[key].update({
"score": new_score,
"level": level,
"interaction_count": self.affinity_data[key]["interaction_count"] + 1
})
return self.affinity_data[key]
def get_affinity_level(self, score: int) -> str:
"""Get affection level based on score"""
if score <= 20:
return "Stranger"
elif score <= 40:
return "Familiar"
elif score <= 60:
return "Friendly"
elif score <= 80:
return "Intimate"
else:
return "Close Friend"This implementation uses LLM to analyze conversation content, automatically judging the player's attitude and adjusting affection. This design makes the affection system more intelligent and natural, players don't need to deliberately please NPCs, just communicate normally.
15.3.3 Affection Affects Dialogue
Affection is not just a number, it should truly affect NPC behavior. In Cyber Town, we modify NPC system prompts to let NPCs adjust reply styles based on current affection levels.
When affection is low, NPCs maintain a polite but distant attitude. When affection increases, NPCs become more enthusiastic and talkative. This change is achieved by dynamically adjusting system prompts.
def create_npc_agent_with_affinity(npc_id: str, name: str, role: str,
personality: str, affinity_level: str):
"""Create NPC Agent with affection"""
# Adjust prompts based on affection level
affinity_prompts = {
"Stranger": "You just met this player, be polite but not overly enthusiastic. Keep replies brief and professional.",
"Familiar": "You already know this player, can have normal exchanges. Replies should be natural and friendly.",
"Friendly": "You treat this player as a friend, willing to share more information. Replies should be detailed and enthusiastic.",
"Intimate": "You trust this player very much, can share private topics. Replies should be full of care.",
"Close Friend": "You treat this player as your best friend, talk about everything. Replies should be cordial and sincere."
}
system_prompt = f"""You are {name}, a {role}.
Your personality traits: {personality}
Current relationship with player: {affinity_level}
{affinity_prompts.get(affinity_level, affinity_prompts["Stranger"])}
You work in the Datawhale office, working with colleagues to promote the development of the open source community.
Please reply naturally based on your role, personality, and relationship with the player.
"""
# Create Agent
llm = HelloAgentsLLM()
agent = SimpleAgent(
name=name,
llm=llm,
system_prompt=system_prompt
)
return agentThis design makes NPC behavior change dynamically with affection. Players can clearly feel that as interactions increase, NPC attitudes towards them are gradually changing, greatly enhancing the game's immersion and fun.