143 lines
3.1 KiB
Go
143 lines
3.1 KiB
Go
//go:build aego_editor
|
|
|
|
package native
|
|
|
|
import (
|
|
"reflect"
|
|
"strconv"
|
|
|
|
"aego/core/ids"
|
|
"aego/core/mathx"
|
|
"aego/editor/core/command"
|
|
"aego/editor/core/context"
|
|
"aego/platform/input"
|
|
"aego/scene"
|
|
"aego/schema"
|
|
"aego/sdk"
|
|
"aego/ui/widgets"
|
|
)
|
|
|
|
func registerEditor(r *sdk.Registry) {
|
|
sdk.EditorHook(r, func(e *sdk.EditorRegistry) error {
|
|
ed := e.Editor()
|
|
if err := e.Inspector("game.Health", sdk.InspectorFunc(healthInspector)); err != nil {
|
|
return err
|
|
}
|
|
if err := e.Panel(sdk.PanelDesc{Panel: &questPanel{ed: ed}, Near: sdk.PanelInspector}); err != nil {
|
|
return err
|
|
}
|
|
return e.Command(sdk.CommandDesc{
|
|
ID: "game.heal_all",
|
|
Name: "Heal All",
|
|
Category: "Game",
|
|
Shortcut: command.Key(input.KeyH, command.ModPrimary|command.ModShift),
|
|
Enabled: func() bool { return ed.Doc() != nil },
|
|
Run: func() error { return heal(ed, healthNodes(ed)) },
|
|
})
|
|
})
|
|
}
|
|
|
|
func healthField(ed *sdk.Editor) (schema.TypeID, schema.FieldID, bool) {
|
|
td, ok := ed.Types.Schema().ByGoType(reflect.TypeFor[Health]())
|
|
if !ok {
|
|
return 0, 0, false
|
|
}
|
|
fd, ok := td.Field("current")
|
|
if !ok {
|
|
return 0, 0, false
|
|
}
|
|
return td.ID, fd.ID, true
|
|
}
|
|
|
|
func healthNodes(ed *sdk.Editor) []ids.NodeID {
|
|
d := ed.Doc()
|
|
if d == nil {
|
|
return nil
|
|
}
|
|
s := d.Scene()
|
|
var out []ids.NodeID
|
|
scene.Query1[Health](s).Each(func(h scene.NodeHandle, _ *Health) {
|
|
out = append(out, s.ID(h))
|
|
})
|
|
return out
|
|
}
|
|
|
|
func heal(ed *sdk.Editor, nodes []ids.NodeID) error {
|
|
d := ed.Doc()
|
|
if d == nil || len(nodes) == 0 {
|
|
return nil
|
|
}
|
|
t, f, ok := healthField(ed)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
s := d.Scene()
|
|
tx := d.History.Begin("Heal")
|
|
for _, n := range nodes {
|
|
hp, ok := scene.Get[Health](s, s.Handle(n))
|
|
if !ok {
|
|
continue
|
|
}
|
|
if err := d.Props.Set(tx, []ids.NodeID{n}, t, f, schema.Float32(hp.Max)); err != nil {
|
|
tx.Abort()
|
|
return err
|
|
}
|
|
}
|
|
tx.Commit()
|
|
return nil
|
|
}
|
|
|
|
func healthInspector(ed *sdk.Editor, nodes []ids.NodeID, defaultFields func()) {
|
|
defaultFields()
|
|
ui := ed.UI
|
|
th := &ui.Theme
|
|
if d := ed.Doc(); d != nil && len(nodes) > 0 {
|
|
s := d.Scene()
|
|
if hp, ok := scene.Get[Health](s, s.Handle(nodes[0])); ok && hp.Max > 0 {
|
|
bar := ui.Cursor().Next(6)
|
|
ui.Rect(bar, th.Widget)
|
|
ui.Rect(mathx.Rect{X: bar.X, Y: bar.Y, W: bar.W * mathx.Clamp(hp.Current/hp.Max, 0, 1), H: bar.H}, th.Ok)
|
|
}
|
|
}
|
|
if widgets.Button(ui, "Heal") {
|
|
if err := heal(ed, nodes); err != nil {
|
|
ed.Notify(context.LevelError, err.Error())
|
|
}
|
|
}
|
|
}
|
|
|
|
type questPanel struct {
|
|
ed *sdk.Editor
|
|
}
|
|
|
|
func (*questPanel) ID() string {
|
|
return "game.quest"
|
|
}
|
|
|
|
func (*questPanel) Title() string {
|
|
return "Quest"
|
|
}
|
|
|
|
func (q *questPanel) Draw(f *sdk.Frame, r mathx.Rect) {
|
|
ui := f.UI
|
|
ed := q.ed
|
|
d := ed.Doc()
|
|
if d == nil {
|
|
widgets.LabelDim(ui, "No scene open")
|
|
return
|
|
}
|
|
s := d.Scene()
|
|
i := 0
|
|
scene.Query1[Health](s).Each(func(h scene.NodeHandle, hp *Health) {
|
|
id := s.ID(h)
|
|
label := s.Name(h) + " " + strconv.Itoa(int(hp.Current)) + " / " + strconv.Itoa(int(hp.Max))
|
|
if widgets.Selectable(ui, ui.IDInt(i), label, ed.IsSelected(id)) {
|
|
ed.Select(id)
|
|
}
|
|
i++
|
|
})
|
|
if i == 0 {
|
|
widgets.LabelDim(ui, "No node has Health yet. Create > Enemy adds one.")
|
|
}
|
|
}
|