last_light/game/model/entity.go

272 lines
5.2 KiB
Go

package model
import (
"mvvasilev/last_light/engine"
"github.com/gdamore/tcell/v2"
"github.com/google/uuid"
)
type Direction int
const (
DirectionNone Direction = iota
North
South
West
East
)
func DirectionName(dir Direction) string {
switch dir {
case North:
return "North"
case South:
return "South"
case West:
return "West"
case East:
return "East"
default:
return "Unknown"
}
}
func MovementDirectionOffset(dir Direction) (int, int) {
switch dir {
case North:
return 0, -1
case South:
return 0, 1
case West:
return -1, 0
case East:
return 1, 0
}
return 0, 0
}
type Entity_NamedComponent struct {
Name string
}
type Entity_DescribedComponent struct {
Description string
}
type Entity_PresentableComponent struct {
Rune rune
Style tcell.Style
}
type Entity_PositionedComponent struct {
Position engine.Position
}
type Entity_EquippedComponent struct {
Inventory *EquippedInventory
}
type Entity_StatsHolderComponent struct {
BaseStats map[Stat]int
}
type Entity_BehaviorComponent struct {
Speed int
Behavior func() (complete, requeue bool)
}
type Entity_HealthComponent struct {
Health int
MaxHealth int
IsDead bool
}
type Entity_DropTableComponent struct {
DropTable *LootTable
}
type Entity_ProjectileComponent struct {
Source Entity
Path *engine.Path
}
type Entity interface {
UniqueId() uuid.UUID
Behavior() *Entity_BehaviorComponent
Named() *Entity_NamedComponent
Described() *Entity_DescribedComponent
Presentable() *Entity_PresentableComponent
Positioned() *Entity_PositionedComponent
Equipped() *Entity_EquippedComponent
Stats() *Entity_StatsHolderComponent
HealthData() *Entity_HealthComponent
DropTable() *Entity_DropTableComponent
Projectile() *Entity_ProjectileComponent
}
type BaseEntity struct {
id uuid.UUID
behavior *Entity_BehaviorComponent
named *Entity_NamedComponent
described *Entity_DescribedComponent
presentable *Entity_PresentableComponent
positioned *Entity_PositionedComponent
equipped *Entity_EquippedComponent
stats *Entity_StatsHolderComponent
damageable *Entity_HealthComponent
dropTable *Entity_DropTableComponent
projectile *Entity_ProjectileComponent
}
func (be *BaseEntity) UniqueId() uuid.UUID {
return be.id
}
func (be *BaseEntity) Named() *Entity_NamedComponent {
return be.named
}
func (be *BaseEntity) Described() *Entity_DescribedComponent {
return be.described
}
func (be *BaseEntity) Presentable() *Entity_PresentableComponent {
return be.presentable
}
func (be *BaseEntity) Positioned() *Entity_PositionedComponent {
return be.positioned
}
func (be *BaseEntity) Equipped() *Entity_EquippedComponent {
return be.equipped
}
func (be *BaseEntity) Stats() *Entity_StatsHolderComponent {
return be.stats
}
func (be *BaseEntity) HealthData() *Entity_HealthComponent {
return be.damageable
}
func (be *BaseEntity) Behavior() *Entity_BehaviorComponent {
return be.behavior
}
func (be *BaseEntity) DropTable() *Entity_DropTableComponent {
return be.dropTable
}
func (be *BaseEntity) Projectile() *Entity_ProjectileComponent {
return be.projectile
}
func CreateEntity(components ...func(*BaseEntity)) *BaseEntity {
e := &BaseEntity{
id: uuid.New(),
}
for _, comp := range components {
comp(e)
}
return e
}
func WithName(name string) func(*BaseEntity) {
return func(e *BaseEntity) {
e.named = &Entity_NamedComponent{
Name: name,
}
}
}
func WithDescription(description string) func(e *BaseEntity) {
return func(e *BaseEntity) {
e.described = &Entity_DescribedComponent{
Description: description,
}
}
}
func WithPresentation(symbol rune, style tcell.Style) func(e *BaseEntity) {
return func(e *BaseEntity) {
e.presentable = &Entity_PresentableComponent{
Rune: symbol,
Style: style,
}
}
}
func WithPosition(pos engine.Position) func(e *BaseEntity) {
return func(e *BaseEntity) {
e.positioned = &Entity_PositionedComponent{
Position: pos,
}
}
}
func WithInventory(inv *EquippedInventory) func(e *BaseEntity) {
return func(e *BaseEntity) {
e.equipped = &Entity_EquippedComponent{
Inventory: inv,
}
}
}
func WithStats(baseStats map[Stat]int, statModifiers ...StatModifier) func(e *BaseEntity) {
return func(e *BaseEntity) {
e.stats = &Entity_StatsHolderComponent{
BaseStats: baseStats,
}
}
}
func WithHealthData(health, maxHealth int, isDead bool) func(e *BaseEntity) {
return func(e *BaseEntity) {
e.damageable = &Entity_HealthComponent{
Health: health,
MaxHealth: maxHealth,
IsDead: isDead,
}
}
}
func WithBehavior(speed int, behavior func(npc Entity) (complete, requeue bool)) func(e *BaseEntity) {
return func(e *BaseEntity) {
e.behavior = &Entity_BehaviorComponent{
Speed: speed,
Behavior: func() (complete bool, requeue bool) {
return behavior(e)
},
}
}
}
func WithDropTable(table map[int]ItemSupplier) func(e *BaseEntity) {
dropTable := CreateLootTable()
for k, v := range table {
dropTable.Add(k, v)
}
return func(e *BaseEntity) {
e.dropTable = &Entity_DropTableComponent{
DropTable: dropTable,
}
}
}
func WithProjectileData(source Entity, path *engine.Path) func(e *BaseEntity) {
return func(e *BaseEntity) {
e.projectile = &Entity_ProjectileComponent{
Source: source,
Path: path,
}
}
}