Files
clawgo/pkg/world/engine_test.go
2026-03-16 21:06:46 +08:00

142 lines
4.4 KiB
Go

package world
import "testing"
func TestVisibleEventsForNPCIncludesNeighborLocationsWithinScope(t *testing.T) {
engine := NewEngine()
state := DefaultWorldState()
npc := NPCState{NPCID: "keeper", CurrentLocation: "commons"}
events := []WorldEvent{
{ID: "a", Type: "noise", LocationID: "square", Content: "neighbor event"},
{ID: "b", Type: "noise", LocationID: "far", Content: "far event"},
}
state.Locations["far"] = Location{ID: "far", Neighbors: []string{}}
out := engine.VisibleEventsForNPC(state, npc, events, 1)
if len(out) != 1 || out[0].ID != "a" {
t.Fatalf("expected only neighbor event, got %+v", out)
}
}
func TestApplyIntentInteractUpdatesEntityState(t *testing.T) {
engine := NewEngine()
state := DefaultWorldState()
state.Entities["fountain"] = Entity{
ID: "fountain",
Name: "Fountain",
LocationID: "square",
State: map[string]interface{}{},
}
npc := &NPCState{NPCID: "merchant", CurrentLocation: "square"}
delta := engine.ApplyIntent(&state, npc, ActionIntent{
ActorID: "merchant",
Action: "interact",
TargetEntity: "fountain",
Speech: "inspects the fountain",
})
if !delta.Applied || delta.Event == nil {
t.Fatalf("expected interact delta to apply, got %+v", delta)
}
entity := state.Entities["fountain"]
if entity.State["last_actor"] != "merchant" {
t.Fatalf("expected entity last_actor updated, got %+v", entity.State)
}
if entity.State["interaction_count"] == nil {
t.Fatalf("expected interaction_count, got %+v", entity.State)
}
}
func TestApplyIntentInteractRejectsDistantEntity(t *testing.T) {
engine := NewEngine()
state := DefaultWorldState()
state.Locations["far"] = Location{ID: "far", Neighbors: []string{}}
state.Entities["orb"] = Entity{
ID: "orb",
LocationID: "far",
}
npc := &NPCState{NPCID: "sage", CurrentLocation: "commons"}
delta := engine.ApplyIntent(&state, npc, ActionIntent{
ActorID: "sage",
Action: "interact",
TargetEntity: "orb",
})
if delta.Applied {
t.Fatalf("expected distant interact to be rejected, got %+v", delta)
}
if delta.Reason != "entity_not_reachable" {
t.Fatalf("unexpected rejection reason: %+v", delta)
}
}
func TestApplyIntentInteractAppliesQuestAndResourceEffects(t *testing.T) {
engine := NewEngine()
state := DefaultWorldState()
state.Entities["chest"] = Entity{
ID: "chest",
LocationID: "square",
State: map[string]interface{}{},
}
npc := &NPCState{NPCID: "rogue", CurrentLocation: "square"}
delta := engine.ApplyIntent(&state, npc, ActionIntent{
ActorID: "rogue",
Action: "interact",
TargetEntity: "chest",
ProposedEffects: map[string]interface{}{
"resource_delta": map[string]interface{}{"gold": 3},
"quest_update": map[string]interface{}{
"id": "find-chest",
"title": "Find The Chest",
"status": "completed",
},
},
})
if !delta.Applied {
t.Fatalf("expected interact to apply, got %+v", delta)
}
resources, ok := state.Entities["chest"].State["resources"].(map[string]int)
if !ok || resources["gold"] != 3 {
t.Fatalf("expected gold resource delta, got %+v", state.Entities["chest"].State)
}
quest := state.ActiveQuests["find-chest"]
if quest.Status != "completed" {
t.Fatalf("expected quest completion, got %+v", quest)
}
}
func TestApplyIntentInteractAppliesEntityPlacementAndLocation(t *testing.T) {
engine := NewEngine()
state := DefaultWorldState()
state.Entities["bench"] = Entity{
ID: "bench",
LocationID: "square",
State: map[string]interface{}{},
}
npc := &NPCState{NPCID: "main", CurrentLocation: "square"}
delta := engine.ApplyIntent(&state, npc, ActionIntent{
ActorID: "main",
Action: "interact",
TargetEntity: "bench",
ProposedEffects: map[string]interface{}{
"entity_location": "commons",
"entity_placement": map[string]interface{}{
"model": "entity.table",
"rotation_y": 1.57,
"offset_x": 0.8,
"offset_z": -0.4,
},
},
})
if !delta.Applied {
t.Fatalf("expected interact to apply, got %+v", delta)
}
entity := state.Entities["bench"]
if entity.LocationID != "commons" {
t.Fatalf("expected entity moved to commons, got %+v", entity)
}
if entity.Placement == nil || entity.Placement.Model != "entity.table" {
t.Fatalf("expected placement model set, got %+v", entity.Placement)
}
if entity.State["rotation_y"] != 1.57 {
t.Fatalf("expected state rotation_y mirrored, got %+v", entity.State)
}
}