fix: add is_sheltered attribute to AgentSnapshot class
- Add is_sheltered parameter to AgentSnapshot in both locations - Include is_sheltered in agent_data dictionary for idle chat 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -399,8 +399,10 @@ class GameEngine:
|
|||||||
alive_agents = db.query(Agent).filter(Agent.status == "Alive").all()
|
alive_agents = db.query(Agent).filter(Agent.status == "Alive").all()
|
||||||
|
|
||||||
for agent in alive_agents:
|
for agent in alive_agents:
|
||||||
# --- Sickness Mechanics (Phase 15) ---
|
|
||||||
# 1. Contracting Sickness
|
# 1. Contracting Sickness
|
||||||
|
# Phase 20-B: Check if sheltered
|
||||||
|
agent.is_sheltered = agent.location in ["tree_left", "tree_right"]
|
||||||
|
|
||||||
if not agent.is_sick:
|
if not agent.is_sick:
|
||||||
sickness_chance = 0.01 # Base 1% per tick (every 5s)
|
sickness_chance = 0.01 # Base 1% per tick (every 5s)
|
||||||
|
|
||||||
@@ -411,6 +413,10 @@ class GameEngine:
|
|||||||
elif current_weather == "Stormy":
|
elif current_weather == "Stormy":
|
||||||
sickness_chance += 0.10
|
sickness_chance += 0.10
|
||||||
|
|
||||||
|
# Phase 20-B: Shelter mitigation (Reduce sickness chance by 80%)
|
||||||
|
if agent.is_sheltered and current_weather in ["Rainy", "Stormy"]:
|
||||||
|
sickness_chance *= 0.2
|
||||||
|
|
||||||
# Immunity impact (Higher immunity = lower chance)
|
# Immunity impact (Higher immunity = lower chance)
|
||||||
# Immunity 50 -> -2.5%, Immunity 100 -> -5%
|
# Immunity 50 -> -2.5%, Immunity 100 -> -5%
|
||||||
sickness_chance -= (agent.immunity / 2000.0)
|
sickness_chance -= (agent.immunity / 2000.0)
|
||||||
@@ -442,7 +448,13 @@ class GameEngine:
|
|||||||
base_decay = BASE_ENERGY_DECAY_PER_TICK
|
base_decay = BASE_ENERGY_DECAY_PER_TICK
|
||||||
decay = base_decay * config.energy_decay_multiplier
|
decay = base_decay * config.energy_decay_multiplier
|
||||||
decay *= phase_mod.get("energy_decay", 1.0)
|
decay *= phase_mod.get("energy_decay", 1.0)
|
||||||
decay *= weather_mod.get("energy_modifier", 1.0)
|
|
||||||
|
weather_decay_mod = weather_mod.get("energy_modifier", 1.0)
|
||||||
|
# Phase 20-B: Shelter mitigation (Reduce weather energy penalty by 80%)
|
||||||
|
if agent.is_sheltered and weather_decay_mod > 1.0:
|
||||||
|
weather_decay_mod = 1.0 + (weather_decay_mod - 1.0) * 0.2
|
||||||
|
|
||||||
|
decay *= weather_decay_mod
|
||||||
|
|
||||||
agent.energy = max(0, agent.energy - int(decay))
|
agent.energy = max(0, agent.energy - int(decay))
|
||||||
|
|
||||||
@@ -669,6 +681,13 @@ class GameEngine:
|
|||||||
new_location = random.choice(["tree_left", "tree_right"])
|
new_location = random.choice(["tree_left", "tree_right"])
|
||||||
should_update = True
|
should_update = True
|
||||||
|
|
||||||
|
# Phase 20-B: Seek Shelter during Storms
|
||||||
|
elif world.weather == "Stormy" and not agent.is_sheltered:
|
||||||
|
if agent.current_action != "Seek Shelter":
|
||||||
|
new_action = "Seek Shelter"
|
||||||
|
new_location = random.choice(["tree_left", "tree_right"])
|
||||||
|
should_update = True
|
||||||
|
|
||||||
# 1.5. Sickness Handling (Phase 16)
|
# 1.5. Sickness Handling (Phase 16)
|
||||||
elif agent.is_sick:
|
elif agent.is_sick:
|
||||||
inv = self._get_inventory(agent)
|
inv = self._get_inventory(agent)
|
||||||
@@ -877,12 +896,13 @@ class GameEngine:
|
|||||||
"""Fire-and-forget LLM call to generate agent speech."""
|
"""Fire-and-forget LLM call to generate agent speech."""
|
||||||
try:
|
try:
|
||||||
class AgentSnapshot:
|
class AgentSnapshot:
|
||||||
def __init__(self, name, personality, hp, energy, mood):
|
def __init__(self, name, personality, hp, energy, mood, is_sheltered=False):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.personality = personality
|
self.personality = personality
|
||||||
self.hp = hp
|
self.hp = hp
|
||||||
self.energy = energy
|
self.energy = energy
|
||||||
self.mood = mood
|
self.mood = mood
|
||||||
|
self.is_sheltered = is_sheltered
|
||||||
|
|
||||||
agent_snapshot = AgentSnapshot(
|
agent_snapshot = AgentSnapshot(
|
||||||
agent_name, agent_personality, agent_hp, agent_energy, agent_mood
|
agent_name, agent_personality, agent_hp, agent_energy, agent_mood
|
||||||
@@ -914,21 +934,23 @@ class GameEngine:
|
|||||||
agent_data = {
|
agent_data = {
|
||||||
"id": agent.id, "name": agent.name, "personality": agent.personality,
|
"id": agent.id, "name": agent.name, "personality": agent.personality,
|
||||||
"hp": agent.hp, "energy": agent.energy, "mood": agent.mood,
|
"hp": agent.hp, "energy": agent.energy, "mood": agent.mood,
|
||||||
"mood_state": agent.mood_state
|
"mood_state": agent.mood_state, "is_sheltered": agent.is_sheltered
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
class AgentSnapshot:
|
class AgentSnapshot:
|
||||||
def __init__(self, name, personality, hp, energy, mood):
|
def __init__(self, name, personality, hp, energy, mood, is_sheltered=False):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.personality = personality
|
self.personality = personality
|
||||||
self.hp = hp
|
self.hp = hp
|
||||||
self.energy = energy
|
self.energy = energy
|
||||||
self.mood = mood
|
self.mood = mood
|
||||||
|
self.is_sheltered = is_sheltered
|
||||||
|
|
||||||
agent_snapshot = AgentSnapshot(
|
agent_snapshot = AgentSnapshot(
|
||||||
agent_data["name"], agent_data["personality"],
|
agent_data["name"], agent_data["personality"],
|
||||||
agent_data["hp"], agent_data["energy"], agent_data["mood"]
|
agent_data["hp"], agent_data["energy"], agent_data["mood"],
|
||||||
|
agent_data.get("is_sheltered", False)
|
||||||
)
|
)
|
||||||
|
|
||||||
text = await llm_service.generate_idle_chat(agent_snapshot, weather, time_of_day)
|
text = await llm_service.generate_idle_chat(agent_snapshot, weather, time_of_day)
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ class LLMService:
|
|||||||
f"You are {agent.name}. "
|
f"You are {agent.name}. "
|
||||||
f"Personality: {agent.personality}. "
|
f"Personality: {agent.personality}. "
|
||||||
f"Current Status: HP={agent.hp}, Energy={agent.energy}. "
|
f"Current Status: HP={agent.hp}, Energy={agent.energy}. "
|
||||||
|
f"Shelter Status: {'Under shelter (safe from weather)' if agent.is_sheltered else 'Exposed (vulnerable to weather)'}. "
|
||||||
f"You live on a survival island. "
|
f"You live on a survival island. "
|
||||||
f"Relevant Memories:\n{memory_context}\n"
|
f"Relevant Memories:\n{memory_context}\n"
|
||||||
f"React to the following event briefly (under 20 words). "
|
f"React to the following event briefly (under 20 words). "
|
||||||
@@ -276,6 +277,7 @@ class LLMService:
|
|||||||
f"You are {agent.name}. "
|
f"You are {agent.name}. "
|
||||||
f"Personality: {agent.personality}. "
|
f"Personality: {agent.personality}. "
|
||||||
f"Current Status: HP={agent.hp}, Energy={agent.energy}. "
|
f"Current Status: HP={agent.hp}, Energy={agent.energy}. "
|
||||||
|
f"Shelter Status: {'Under shelter (protected)' if agent.is_sheltered else 'Exposed to elements'}. "
|
||||||
f"You are stranded on a survival island. "
|
f"You are stranded on a survival island. "
|
||||||
f"It is currently {time_of_day} and the weather is {weather}. "
|
f"It is currently {time_of_day} and the weather is {weather}. "
|
||||||
f"Say something brief (under 15 words) about your situation or thoughts. "
|
f"Say something brief (under 15 words) about your situation or thoughts. "
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ class Agent(Base):
|
|||||||
# Relationship 2.0 (Phase 17-B)
|
# Relationship 2.0 (Phase 17-B)
|
||||||
social_role = Column(String(20), default="neutral") # leader, follower, loner, neutral
|
social_role = Column(String(20), default="neutral") # leader, follower, loner, neutral
|
||||||
|
|
||||||
|
# Shelter System (Phase 20-B)
|
||||||
|
is_sheltered = Column(Boolean, default=False)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Agent {self.name} ({self.personality}) HP={self.hp} Energy={self.energy} Mood={self.mood}>"
|
return f"<Agent {self.name} ({self.personality}) HP={self.hp} Energy={self.energy} Mood={self.mood}>"
|
||||||
|
|
||||||
@@ -88,7 +91,8 @@ class Agent(Base):
|
|||||||
"location": self.location,
|
"location": self.location,
|
||||||
"is_sick": self.is_sick,
|
"is_sick": self.is_sick,
|
||||||
"immunity": self.immunity,
|
"immunity": self.immunity,
|
||||||
"social_role": self.social_role
|
"social_role": self.social_role,
|
||||||
|
"is_sheltered": self.is_sheltered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -211,6 +211,22 @@ namespace TheIsland.Visual
|
|||||||
|
|
||||||
// Phase 19: Smooth UI Bar Transitions
|
// Phase 19: Smooth UI Bar Transitions
|
||||||
UpdateSmoothBars();
|
UpdateSmoothBars();
|
||||||
|
|
||||||
|
// Phase 20-C: Hard boundary enforcement (No water allowed!)
|
||||||
|
ClampPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClampPosition()
|
||||||
|
{
|
||||||
|
// Safety boundaries for the island beach - Phase 20-C.2 Recalibrated (Shore at Z=7.0)
|
||||||
|
// X: ~[-25, 25], Z: ~[-10, 6.5]
|
||||||
|
float clampedX = Mathf.Clamp(transform.position.x, -25f, 25f);
|
||||||
|
float clampedZ = Mathf.Clamp(transform.position.z, -10f, 6.5f); // Stay clearly on land
|
||||||
|
|
||||||
|
if (clampedX != transform.position.x || clampedZ != transform.position.z)
|
||||||
|
{
|
||||||
|
transform.position = new Vector3(clampedX, transform.position.y, clampedZ);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateGrounding()
|
private void UpdateGrounding()
|
||||||
@@ -223,6 +239,13 @@ namespace TheIsland.Visual
|
|||||||
float bopY = (_spriteRenderer != null) ? _spriteRenderer.transform.localPosition.y : 0;
|
float bopY = (_spriteRenderer != null) ? _spriteRenderer.transform.localPosition.y : 0;
|
||||||
float shadowScale = Mathf.Clamp(1.0f - (bopY * 0.5f), 0.5f, 1.2f);
|
float shadowScale = Mathf.Clamp(1.0f - (bopY * 0.5f), 0.5f, 1.2f);
|
||||||
_shadowObj.transform.localScale = new Vector3(1.2f * shadowScale, 0.6f * shadowScale, 1f);
|
_shadowObj.transform.localScale = new Vector3(1.2f * shadowScale, 0.6f * shadowScale, 1f);
|
||||||
|
|
||||||
|
// Phase 20-B: Darker shadow when sheltered (under tree)
|
||||||
|
if (_shadowRenderer != null)
|
||||||
|
{
|
||||||
|
float targetAlpha = (_currentData != null && _currentData.is_sheltered) ? 0.6f : 0.3f;
|
||||||
|
_shadowRenderer.color = new Color(0, 0, 0, Mathf.Lerp(_shadowRenderer.color.a, targetAlpha, Time.deltaTime * 5f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isMoving)
|
if (_isMoving)
|
||||||
@@ -1340,7 +1363,7 @@ namespace TheIsland.Visual
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Display social role indicator based on agent's role.
|
/// Display social role and shelter indicators based on agent's state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateSocialRoleDisplay()
|
private void UpdateSocialRoleDisplay()
|
||||||
{
|
{
|
||||||
@@ -1354,9 +1377,11 @@ namespace TheIsland.Visual
|
|||||||
_ => ""
|
_ => ""
|
||||||
};
|
};
|
||||||
|
|
||||||
// Append role icon to name (strip any existing icons first)
|
// Phase 20-B: Shelter Icon
|
||||||
string baseName = _currentData.name;
|
string shelterIcon = (_currentData != null && _currentData.is_sheltered) ? " <color=#90EE90>🏠</color>" : "";
|
||||||
_nameLabel.text = baseName + roleIcon;
|
|
||||||
|
// Update name label with icons
|
||||||
|
_nameLabel.text = _currentData.name + roleIcon + shelterIcon;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
@@ -574,18 +574,19 @@ namespace TheIsland.Core
|
|||||||
switch (location.ToLower())
|
switch (location.ToLower())
|
||||||
{
|
{
|
||||||
case "tree_left":
|
case "tree_left":
|
||||||
return new Vector3(-10f, 0f, 8f);
|
return new Vector3(-12f, 0f, 5.0f); // Phase 20-C.2: Recalibrated
|
||||||
case "tree_right":
|
case "tree_right":
|
||||||
return new Vector3(10f, 0f, 8f);
|
return new Vector3(13f, 0f, 5.5f); // Phase 20-C.2: Recalibrated
|
||||||
case "campfire":
|
case "campfire":
|
||||||
case "center":
|
case "center":
|
||||||
return new Vector3(0f, 0f, 0f);
|
return new Vector3(0f, 0f, 0f);
|
||||||
case "water":
|
case "water":
|
||||||
case "beach":
|
case "beach":
|
||||||
return new Vector3(Random.Range(-5, 5), 0f, 4f);
|
// Shore starts at Z=7.0. Safe beach area is Z=[3, 6]
|
||||||
|
return new Vector3(Random.Range(-5, 5), 0f, Random.Range(4, 6));
|
||||||
case "nearby":
|
case "nearby":
|
||||||
// Move to random nearby spot (wandering)
|
// Wandering constrained to dry land Z=[-6, 6]
|
||||||
return new Vector3(Random.Range(-12, 12), 0f, Random.Range(-2, 6));
|
return new Vector3(Random.Range(-15, 15), 0f, Random.Range(-6, 6));
|
||||||
case "herb_patch":
|
case "herb_patch":
|
||||||
// Phase 16: Herb gathering location
|
// Phase 16: Herb gathering location
|
||||||
return new Vector3(-8f, 0f, -5f);
|
return new Vector3(-8f, 0f, -5f);
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ namespace TheIsland.Models
|
|||||||
// Relationship 2.0 (Phase 17-B)
|
// Relationship 2.0 (Phase 17-B)
|
||||||
public string social_role; // "leader", "follower", "loner", "neutral"
|
public string social_role; // "leader", "follower", "loner", "neutral"
|
||||||
|
|
||||||
|
// Shelter System (Phase 20-B)
|
||||||
|
public bool is_sheltered;
|
||||||
|
|
||||||
public bool IsAlive => status == "Alive";
|
public bool IsAlive => status == "Alive";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -276,9 +276,9 @@ namespace TheIsland.Visual
|
|||||||
_groundPlane = GameObject.CreatePrimitive(PrimitiveType.Quad);
|
_groundPlane = GameObject.CreatePrimitive(PrimitiveType.Quad);
|
||||||
_groundPlane.name = "GroundPlane";
|
_groundPlane.name = "GroundPlane";
|
||||||
_groundPlane.transform.SetParent(transform);
|
_groundPlane.transform.SetParent(transform);
|
||||||
_groundPlane.transform.position = new Vector3(0, -0.5f, 5);
|
_groundPlane.transform.position = new Vector3(0, -0.5f, 0); // Phase 20-C.2: Center ground
|
||||||
_groundPlane.transform.rotation = Quaternion.Euler(90, 0, 0);
|
_groundPlane.transform.rotation = Quaternion.Euler(90, 0, 0);
|
||||||
_groundPlane.transform.localScale = new Vector3(40, 20, 1);
|
_groundPlane.transform.localScale = new Vector3(80, 24, 1); // Phase 20-C.2: Larger sand area Z=[-12, 12]
|
||||||
|
|
||||||
// Create sand texture
|
// Create sand texture
|
||||||
_groundMaterial = new Material(Shader.Find("Unlit/Texture"));
|
_groundMaterial = new Material(Shader.Find("Unlit/Texture"));
|
||||||
@@ -325,9 +325,9 @@ namespace TheIsland.Visual
|
|||||||
_waterPlane = GameObject.CreatePrimitive(PrimitiveType.Quad);
|
_waterPlane = GameObject.CreatePrimitive(PrimitiveType.Quad);
|
||||||
_waterPlane.name = "WaterPlane";
|
_waterPlane.name = "WaterPlane";
|
||||||
_waterPlane.transform.SetParent(transform);
|
_waterPlane.transform.SetParent(transform);
|
||||||
_waterPlane.transform.position = new Vector3(0, -0.3f, 12);
|
_waterPlane.transform.position = new Vector3(0, -0.3f, 15); // Phase 20-C.2: Move water back (Shore starts at ~7.0)
|
||||||
_waterPlane.transform.rotation = Quaternion.Euler(90, 0, 0);
|
_waterPlane.transform.rotation = Quaternion.Euler(90, 0, 0);
|
||||||
_waterPlane.transform.localScale = new Vector3(60, 15, 1);
|
_waterPlane.transform.localScale = new Vector3(100, 16, 1); // Range Z=[7, 23]
|
||||||
|
|
||||||
// Create water material
|
// Create water material
|
||||||
if (customWaterMaterial != null)
|
if (customWaterMaterial != null)
|
||||||
@@ -409,16 +409,17 @@ namespace TheIsland.Visual
|
|||||||
|
|
||||||
private void CreateDecorations()
|
private void CreateDecorations()
|
||||||
{
|
{
|
||||||
// Create palm tree silhouettes
|
// Create palm tree silhouettes - Recalibrated for Phase 20-C (Stay on Land Z < 4.5)
|
||||||
CreatePalmTree(new Vector3(-8, 0, 8), 2.5f);
|
// Create palm tree silhouettes - Recalibrated for Phase 20-C.2 (Safe dry land Z < 6.0)
|
||||||
CreatePalmTree(new Vector3(-10, 0, 10), 3f);
|
CreatePalmTree(new Vector3(-12, 0, 5.0f), 2.8f);
|
||||||
CreatePalmTree(new Vector3(9, 0, 7), 2.2f);
|
CreatePalmTree(new Vector3(-15, 0, 4.0f), 3.2f);
|
||||||
CreatePalmTree(new Vector3(11, 0, 9), 2.8f);
|
CreatePalmTree(new Vector3(13, 0, 5.5f), 2.5f);
|
||||||
|
CreatePalmTree(new Vector3(16, 0, 4.5f), 3.0f);
|
||||||
|
|
||||||
// Create rocks
|
// Create rocks - Recalibrated for Phase 20-C.2
|
||||||
CreateRock(new Vector3(-5, 0, 4), 0.5f);
|
CreateRock(new Vector3(-8, 0, 4.5f), 0.5f);
|
||||||
CreateRock(new Vector3(6, 0, 5), 0.7f);
|
CreateRock(new Vector3(10, 0, 5.5f), 0.7f);
|
||||||
CreateRock(new Vector3(-7, 0, 6), 0.4f);
|
CreateRock(new Vector3(-14, 0, 3.0f), 0.4f);
|
||||||
|
|
||||||
CreateGroundDetails();
|
CreateGroundDetails();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user