Browse Source

Added some of the Object structure

Object currently can render for KPlayer and KCreature... to a degree... I need to change it so it can render the Location's name, and Owner's name (Even if Owner is not a KPlayer but a KGuild)

I'll also need it so I can render the Inventory by Object Name and maybe determine it's ? (SubKind?)

(Item SubKinds: Weapon, Armor, Currency, Potion, Scroll, SpellBook, etc.)
david 6 months ago
parent
commit
a6db78412c
6 changed files with 245 additions and 1 deletions
  1. 1 1
      README.md
  2. 3 0
      go.mod
  3. 34 0
      main.go
  4. 77 0
      objects.go
  5. 21 0
      traits.go
  6. 109 0
      types.go

+ 1 - 1
README.md

@@ -1,2 +1,2 @@
-# lunar-mud
+# Lunar MUD
 

+ 3 - 0
go.mod

@@ -0,0 +1,3 @@
+module git.red-green.com/david/lunar-mud
+
+go 1.23.2

+ 34 - 0
main.go

@@ -0,0 +1,34 @@
+package main
+
+import (
+	"fmt"
+	"strings"
+)
+
+func main() {
+	var o Object = Object{
+		Id:          1,
+		Kind:        KPlayer,
+		Name:        "Bob",
+		Description: "Hello World!",
+		Password:    "12345",
+		Location:    2,
+		Owner:       0,
+		Health:      ValueRange{Value: 10, Max: 10},
+		Magic:       ValueRange{Value: 0, Max: 0},
+		BuildPoints: ValueRange{Value: 3, Max: 10},
+		Level:       1,
+		Experience:  ValueRange{Value: 0, Max: 80},
+		Inventory: map[Id]uint64{
+			3: 1,
+		},
+		Exits:          make(map[string]Id),
+		Motd:           "",
+		CoOwner:        0,
+		SeniorOfficers: []Id{},
+		Officers:       []Id{},
+		Members:        []Id{},
+	}
+	fmt.Printf("o is %v\r\n", o.valid())
+	fmt.Printf("%s", strings.ReplaceAll(o.render(), "\n", "\r\n"))
+}

+ 77 - 0
objects.go

@@ -0,0 +1,77 @@
+package main
+
+import "fmt"
+
+type Object struct {
+	// Required
+
+	Id   Id
+	Kind Kind
+	Name string
+
+	// Optional (Based on Kind)
+
+	Description    string
+	Password       string
+	Location       Id
+	Owner          Id
+	Health         ValueRange
+	Magic          ValueRange
+	BuildPoints    ValueRange
+	Level          uint16
+	Experience     ValueRange
+	Inventory      map[Id]uint64
+	Exits          map[string]Id
+	Motd           string
+	CoOwner        Id
+	SeniorOfficers []Id
+	Officers       []Id
+	Members        []Id
+}
+
+func (o *Object) valid() bool {
+	if o.Kind == KPlayer && len(o.Password) == 0 {
+		return false
+	}
+	return IsValid(o.Id) && IsValid(o.Kind) && len(o.Name) != 0
+}
+
+func (o *Object) render() string {
+	var out string = ""
+	switch o.Kind {
+	case KPlayer, KCreature:
+		out += fmt.Sprintf("%s the %s (%s)", o.Name, o.Kind.render(), o.Id.render())
+		out += "\n"
+		if len(o.Description) != 0 {
+			out += fmt.Sprintf("%s", o.Description)
+			out += "\n"
+		}
+		if IsValid(o.Location) {
+			out += fmt.Sprintf("Located at %s", o.Location.render())
+			out += "\n"
+		}
+		if IsValid(o.Owner) {
+			out += fmt.Sprintf("Owned by %s", o.Owner.render())
+			out += "\n"
+		}
+		if IsValid(o.Health) {
+			out += fmt.Sprintf("%s Health", o.Health.render())
+			out += "\n"
+		}
+		if IsValid(o.Magic) {
+			out += fmt.Sprintf("%s Magic Points", o.Magic.render())
+			out += "\n"
+		}
+		if IsValid(o.BuildPoints) {
+			out += fmt.Sprintf("%s Build Points", o.BuildPoints.render())
+			out += "\n"
+		}
+		if o.Level != 0 && o.Experience.Max != 0 {
+			out += fmt.Sprintf("Level %d and %s Experience Points", o.Level, o.Experience.render())
+			out += "\n"
+		}
+	default:
+		return "Object.render() >> Unknown/Unsupported Kind"
+	}
+	return out
+}

+ 21 - 0
traits.go

@@ -0,0 +1,21 @@
+package main
+
+// Determines validity of something
+type Valid interface {
+	valid() bool
+}
+
+// Verifies validity of something
+func IsValid(v Valid) bool {
+	return v.valid()
+}
+
+// Verifies invalidity of something
+func IsInvalid(v Valid) bool {
+	return !v.valid()
+}
+
+// Attempt to merge all rendering code into one method (which could then be chained)
+type Render interface {
+	render() string
+}

+ 109 - 0
types.go

@@ -0,0 +1,109 @@
+package main
+
+import "fmt"
+
+// Identification Number
+//
+// Used to separate things into a unique thing
+type Id uint64
+
+// An Id is considered valid so long as it's not 0
+func (i Id) valid() bool {
+	return i != 0
+}
+
+// Render of an Id is simply prefixing it with #
+//
+// i.e. Id=5  .render()  "#5"
+func (i Id) render() string {
+	return fmt.Sprintf("#%d", i)
+}
+
+// Kind is used to separate a general Object into specific categories
+//
+// Players, Guilds, Rooms, Items, Creatures, Vehicles
+//
+// e.g. Players, Items, Creatures and Vehicles have a "health" (Items and Vehicles use the same name for their durability)
+//
+// But a Room won't use "health" (Despite it existing)
+type Kind uint8
+
+// A Kind is valid so long as it's not 0 or None
+func (k Kind) valid() bool {
+	return k != KNone
+}
+
+// Renders the Kind as a name
+//
+// i.e. Kind=Guild (2)  .render()  "Guild"
+func (k Kind) render() string {
+	switch k {
+	case KPlayer:
+		return "Player"
+	case KGuild:
+		return "Guild"
+	case KRoom:
+		return "Room"
+	case KItem:
+		return "Item"
+	case KCreature:
+		return "Creature"
+	case KVehicle:
+		return "Vehicle"
+	default:
+		return "Unknown"
+	}
+}
+
+const (
+	// An Invalid Kind
+	KNone Kind = iota
+	// A Creature, but controlled by a Human
+	KPlayer
+	// A Collection of 1 or more Players (Inventory is shared among Players, etc.)
+	KGuild
+	// A Room, which can hold Players, Items, Creatures, Vehicles and Containers
+	KRoom
+	// A Item, This is broad, but most Items should specify a specific thing (Weapon's for instance would have a "damage", Armor "defense", Gold on the other hand might have "value")
+	KItem
+	// A Entity that is controlled by either a Human's Logic (Scripted in some manner), or by the computer (Scripted internally)
+	KCreature
+	// A Entity / Room Hybrid, it behaves like both a Room and a Creature, Players and Creatures can enter a Vehicle, then where ever the Vehicle goes they are moved along with it
+	KVehicle
+)
+
+// A ValueRange is something which has a current Value and a Max
+//
+// Some ValueRanges are Health, Magic, and Build Points
+type ValueRange struct {
+	Value uint64
+	Max   uint64
+}
+
+// ValueRanges are invalid when Max is 0, or Value is greater than Max
+func (v ValueRange) valid() bool {
+	if v.Max == 0 {
+		return false
+	}
+	return v.Value <= v.Max
+}
+
+// A 0 to 100 of the percentage the Range is at based on Value and Max
+//
+// This method will return 0 if the ValueRange is invalid
+func (v *ValueRange) Percent() uint8 {
+	if IsInvalid(v) {
+		return 0
+	}
+	return uint8((float32(v.Value) / float32(v.Max)) * 100.0)
+}
+
+// Forms a good default for a ValueRange
+//
+// i.e. ValueRange{Value: 5, Max: 10}  .render()  "5/10"
+func (v ValueRange) render() string {
+	if IsInvalid(v) {
+		return ""
+	}
+	return fmt.Sprintf("%d/%d", v.Value, v.Max)
+}