package entity import ( "path/filepath" "testing" ) // TestBreed 动物繁殖:成年+冷却完成 → 幼崽;冷却中拒绝;上限拒绝(动物体系.md §3)。 func TestBreed(t *testing.T) { m := NewManager() w := flatWorld{} a := m.Spawn(KindAnimal, 0.5, 63, 0.5) a.Data = &Animal{Species: 1} b := m.Spawn(KindAnimal, 1.5, 63, 0.5) b.Data = &Animal{Species: 1} baby := m.Breed(a, b, w) if baby == nil { t.Fatal("应繁殖出幼崽") } if d, ok := baby.Data.(*Animal); !ok || d.GrowthTicks == 0 || d.Species != 1 { t.Fatalf("幼崽数据异常: %+v", baby.Data) } // 冷却中:拒绝 if m.Breed(a, b, w) != nil { t.Fatal("冷却中不应繁殖") } // 冷却恢复后可再次繁殖 ad := a.Data.(*Animal) ad.BreedCooldown = 0 bd := b.Data.(*Animal) bd.BreedCooldown = 0 if m.Breed(a, b, w) == nil { t.Fatal("冷却结束后应能繁殖") } } // TestBreedCap 每区块上限(动物体系.md §7 防无限繁殖)。 func TestBreedCap(t *testing.T) { m := NewManager() w := flatWorld{} a := m.Spawn(KindAnimal, 0.5, 63, 0.5) a.Data = &Animal{Species: 0} b := m.Spawn(KindAnimal, 1.5, 63, 0.5) b.Data = &Animal{Species: 0} for i := 0; i < 12; i++ { m.Spawn(KindAnimal, 2.5, 63, 2.5+float64(i)) } if m.Breed(a, b, w) != nil { t.Fatal("超上限不应繁殖") } } func TestAnimalSpeciesFallback(t *testing.T) { e := &Entity{ID: 6, Kind: KindAnimal} if AnimalSpecies(e) != 2 { t.Fatalf("无 Data 应回退 ID%%4=2,实际 %d", AnimalSpecies(e)) } e.Data = &Animal{Species: 3} if AnimalSpecies(e) != 3 { t.Fatalf("应读 Species 字段,实际 %d", AnimalSpecies(e)) } } func TestBreedCrossSpecies(t *testing.T) { m := NewManager() w := flatWorld{} a := m.Spawn(KindAnimal, 0.5, 63, 0.5) a.Data = &Animal{Species: 0} b := m.Spawn(KindAnimal, 1.5, 63, 0.5) b.Data = &Animal{Species: 2} if m.Breed(a, b, w) != nil { t.Fatal("异种不应繁殖") } } // TestLoadTrades 交易表解析与职业查询(村民系统.md §7)。 func TestFeedAndLove(t *testing.T) { e := &Entity{Kind: KindAnimal, Data: &Animal{Species: 0}} if !Feed(e) { t.Fatal("成年牛应能喂食") } if e.Data.(*Animal).LoveTicks <= 0 { t.Fatal("喂食应进入 love") } baby := &Entity{Kind: KindAnimal, Data: &Animal{Species: 0, GrowthTicks: 10}} if Feed(baby) { t.Fatal("幼崽不应进入繁殖") } } func TestShearAndMilk(t *testing.T) { sheep := &Entity{Kind: KindAnimal, Data: &Animal{Species: 2}} if !ShearSheep(sheep, 2) { t.Fatal("羊应能剪毛") } if !sheep.Data.(*Animal).Sheared { t.Fatal("剪后应标记 Sheared") } if ShearSheep(sheep, 1) { t.Fatal("已剪不应再剪") } cow := &Entity{Kind: KindAnimal, Data: &Animal{Species: 0}} if !MilkCow(cow) { t.Fatal("牛应能挤奶") } if MilkCow(sheep) { t.Fatal("羊不能挤奶") } } func TestLoadTrades(t *testing.T) { tbl, err := LoadTrades(filepath.Join("..", "..", "assets", "config", "villager_trades.json")) if err != nil { t.Fatalf("加载交易表失败: %v", err) } if offers := tbl.OffersFor(0); len(offers) != 2 { t.Fatalf("农民交易期望 2 条,实际 %d", len(offers)) } if offers := tbl.OffersFor(2); len(offers) != 2 || offers[0].Buy != "coal" { t.Fatalf("铁匠交易异常: %+v", offers) } }