Noah Petherbridge
94d0da78e7
Water pixels finally do something other than turn your character blue! * When the player character is "wet" (touching water pixels, and so appearing in a blue mask), water physics apply: gravity is slower, your jump height is halved, but you get infinite jumps to swim higher in the water. * Holding the jump key under water will incur a short delay between jumps, so that you don't just fly straight up to the surface. Tap the jump button to move up quicker, you can spam it all you want. Azulians are also able to handle being under water: * They'll sink to the bottom and keep walking back and forth normally. * If you are above them and noticed, they'll jump (swim) up towards you, aware of the water and it jumps like you do. * The Blue Azulian has the poorest vertical aggro range so it isn't a very good swimmer. The White Azulian is very good at navigating water as it can pursue the player from the furthest distance of them all. Changes to the editor: * New brush pattern added: bubbles.png * It's the default pattern now for the "water" color of all of the built-in palettes instead of ink.png * A repeating pattern of bubbles carved out showing the level wallpaper. * The old "Bubbles (circles.png)" is renamed "Circles" * The last scroll position is saved with the Level file, so when you reload the level later it's scrolled at where you left it.
137 lines
3.8 KiB
Go
137 lines
3.8 KiB
Go
package uix
|
|
|
|
import (
|
|
"git.kirsle.net/apps/doodle/pkg/doodads"
|
|
"git.kirsle.net/apps/doodle/pkg/level"
|
|
"git.kirsle.net/apps/doodle/pkg/log"
|
|
"git.kirsle.net/apps/doodle/pkg/scripting"
|
|
"git.kirsle.net/go/render"
|
|
)
|
|
|
|
// Functions relating to the Doodad JavaScript API for Canvas Actors.
|
|
|
|
// MakeScriptAPI makes several useful globals available to doodad
|
|
// scripts such as Actors.At()
|
|
func (w *Canvas) MakeScriptAPI(vm *scripting.VM) {
|
|
vm.Set("Actors", map[string]interface{}{
|
|
// Actors.At(Point)
|
|
"At": func(p render.Point) []*Actor {
|
|
var result = []*Actor{}
|
|
|
|
for _, actor := range w.actors {
|
|
var box = actor.Hitbox().AddPoint(actor.Position())
|
|
if actor != nil && p.Inside(box) {
|
|
result = append(result, actor)
|
|
}
|
|
}
|
|
|
|
return result
|
|
},
|
|
|
|
// Actors.FindPlayer: returns the nearest player character.
|
|
"FindPlayer": func() *Actor {
|
|
for _, actor := range w.actors {
|
|
if actor.IsPlayer() {
|
|
return actor
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
|
|
// Actors.New: create a new actor.
|
|
"New": func(filename string) *Actor {
|
|
doodad, err := doodads.LoadFile(filename)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
actor := NewActor("_new", &level.Actor{}, doodad)
|
|
w.AddActor(actor)
|
|
|
|
// Set up the player character's script in the VM.
|
|
if err := w.scripting.AddLevelScript(actor.ID(), filename); err != nil {
|
|
log.Error("Actors.New(%s): scripting.InstallActor(player) failed: %s", filename, err)
|
|
}
|
|
|
|
return actor
|
|
},
|
|
|
|
// Actors.SetPlayerCharacter: remake the player character.
|
|
"SetPlayerCharacter": func(filename string) {
|
|
if w.OnSetPlayerCharacter != nil {
|
|
w.OnSetPlayerCharacter(filename)
|
|
} else {
|
|
log.Error("Actors.SetPlayerCharacter: caller was not ready")
|
|
}
|
|
},
|
|
})
|
|
|
|
vm.Set("Level", map[string]interface{}{
|
|
"Difficulty": w.level.GameRule.Difficulty,
|
|
"ResetTimer": func() {
|
|
if w.OnResetTimer != nil {
|
|
w.OnResetTimer()
|
|
} else {
|
|
log.Error("Level.ResetTimer: caller was not ready")
|
|
}
|
|
},
|
|
})
|
|
}
|
|
|
|
// MakeSelfAPI generates the `Self` object for the scripting API in
|
|
// reference to a live Canvas actor in the level.
|
|
func (w *Canvas) MakeSelfAPI(actor *Actor) map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"Filename": actor.Doodad().Filename,
|
|
"Title": actor.Doodad().Title,
|
|
|
|
// functions
|
|
"ID": actor.ID,
|
|
"Size": func() render.Rect {
|
|
var size = actor.Doodad().ChunkSize()
|
|
return render.NewRect(size, size)
|
|
},
|
|
"GetTag": actor.Doodad().Tag,
|
|
"Position": actor.Position,
|
|
"MoveTo": func(p render.Point) {
|
|
actor.MoveTo(p)
|
|
actor.SetGrounded(false)
|
|
},
|
|
"Grounded": actor.Grounded,
|
|
"SetHitbox": actor.SetHitbox,
|
|
"Hitbox": actor.Hitbox,
|
|
"SetVelocity": actor.SetVelocity,
|
|
"GetVelocity": actor.Velocity,
|
|
"SetMobile": actor.SetMobile,
|
|
"SetInventory": actor.SetInventory,
|
|
"HasInventory": actor.HasInventory,
|
|
"SetGravity": actor.SetGravity,
|
|
"Invulnerable": actor.Invulnerable,
|
|
"SetInvulnerable": actor.SetInvulnerable,
|
|
"AddAnimation": actor.AddAnimation,
|
|
"IsAnimating": actor.IsAnimating,
|
|
"IsPlayer": actor.IsPlayer,
|
|
"PlayAnimation": actor.PlayAnimation,
|
|
"StopAnimation": actor.StopAnimation,
|
|
"ShowLayer": actor.ShowLayer,
|
|
"ShowLayerNamed": actor.ShowLayerNamed,
|
|
"Inventory": actor.Inventory,
|
|
"AddItem": actor.AddItem,
|
|
"RemoveItem": actor.RemoveItem,
|
|
"HasItem": actor.HasItem,
|
|
"ClearInventory": actor.ClearInventory,
|
|
"Destroy": actor.Destroy,
|
|
"Freeze": actor.Freeze,
|
|
"Unfreeze": actor.Unfreeze,
|
|
"IsWet": actor.IsWet,
|
|
"Hide": actor.Hide,
|
|
"Show": actor.Show,
|
|
"GetLinks": func() []map[string]interface{} {
|
|
var result = []map[string]interface{}{}
|
|
for _, linked := range w.GetLinkedActors(actor) {
|
|
result = append(result, w.MakeSelfAPI(linked))
|
|
}
|
|
return result
|
|
},
|
|
}
|
|
}
|