Doodads: Use Key and Working Warp Doors
* The "Use Key" (Q or Spacebar) now activates the Warp Door instead of a collision event doing so. * Warp Doors are now functional: the player opens a door, disappears, the door closes; player is teleported to the linked door which opens, appears the player and closes. * If the player exits thru a Blue or Orange door which is disabled (dotted outline), the door still opens and drops the player off but returns to a Disabled state, acting as a one-way door. * Clean up several debug log lines from Doodle and doodad scripts.
This commit is contained in:
parent
2c1185cc9f
commit
3892087932
|
@ -1,6 +1,4 @@
|
||||||
function main() {
|
function main() {
|
||||||
console.log("Azulian '%s' initialized!", Self.Title);
|
|
||||||
|
|
||||||
var playerSpeed = 4;
|
var playerSpeed = 4;
|
||||||
var gravity = 4;
|
var gravity = 4;
|
||||||
var Vx = Vy = 0;
|
var Vx = Vy = 0;
|
||||||
|
|
|
@ -4,8 +4,6 @@ function main() {
|
||||||
var Vx = Vy = 0;
|
var Vx = Vy = 0;
|
||||||
var altitude = Self.Position().Y; // original height in the level
|
var altitude = Self.Position().Y; // original height in the level
|
||||||
|
|
||||||
console.log("Bird altitude is %d", altitude);
|
|
||||||
|
|
||||||
var direction = "left";
|
var direction = "left";
|
||||||
var states = {
|
var states = {
|
||||||
flying: 0,
|
flying: 0,
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
function main() {
|
function main() {
|
||||||
console.log("%s initialized!", Self.Title);
|
|
||||||
|
|
||||||
var timer = 0;
|
var timer = 0;
|
||||||
var pressed = false;
|
var pressed = false;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
function main() {
|
function main() {
|
||||||
console.log("%s initialized!", Self.Title);
|
|
||||||
|
|
||||||
var pressed = false;
|
var pressed = false;
|
||||||
|
|
||||||
// When a sticky button receives power, it pops back up.
|
// When a sticky button receives power, it pops back up.
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
function main() {
|
function main() {
|
||||||
console.log("%s initialized!", Self.Title);
|
|
||||||
|
|
||||||
Self.AddAnimation("open", 100, [0, 1, 2, 3]);
|
Self.AddAnimation("open", 100, [0, 1, 2, 3]);
|
||||||
Self.AddAnimation("close", 100, [3, 2, 1, 0]);
|
Self.AddAnimation("close", 100, [3, 2, 1, 0]);
|
||||||
var animating = false;
|
var animating = false;
|
||||||
|
@ -9,8 +7,6 @@ function main() {
|
||||||
Self.SetHitbox(0, 0, 34, 76);
|
Self.SetHitbox(0, 0, 34, 76);
|
||||||
|
|
||||||
Message.Subscribe("power", function(powered) {
|
Message.Subscribe("power", function(powered) {
|
||||||
console.log("%s got power=%+v", Self.Title, powered);
|
|
||||||
|
|
||||||
if (powered) {
|
if (powered) {
|
||||||
if (animating || opened) {
|
if (animating || opened) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Exit Flag.
|
// Exit Flag.
|
||||||
function main() {
|
function main() {
|
||||||
console.log("%s initialized!", Self.Title);
|
|
||||||
Self.SetHitbox(22+16, 16, 75-16, 86);
|
Self.SetHitbox(22+16, 16, 75-16, 86);
|
||||||
|
|
||||||
Events.OnCollide(function(e) {
|
Events.OnCollide(function(e) {
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
var state = false;
|
var state = false;
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
console.log("%s ID '%s' initialized!", Self.Title, Self.ID());
|
|
||||||
Self.SetHitbox(0, 0, 42, 42);
|
Self.SetHitbox(0, 0, 42, 42);
|
||||||
|
|
||||||
// When the button is activated, don't keep toggling state until we're not
|
// When the button is activated, don't keep toggling state until we're not
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
function main() {
|
function main() {
|
||||||
console.log("%s initialized!", Self.Title);
|
|
||||||
|
|
||||||
// Switch has two frames:
|
// Switch has two frames:
|
||||||
// 0: Off
|
// 0: Off
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
function main() {
|
function main() {
|
||||||
console.log("%s initialized!", Self.Title);
|
|
||||||
|
|
||||||
var timer = 0;
|
var timer = 0;
|
||||||
|
|
||||||
Self.SetHitbox(0, 0, 72, 6);
|
Self.SetHitbox(0, 0, 72, 6);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
function main() {
|
function main() {
|
||||||
// What direction is the trapdoor facing?
|
// What direction is the trapdoor facing?
|
||||||
var direction = Self.GetTag("direction");
|
var direction = Self.GetTag("direction");
|
||||||
console.log("Trapdoor(%s) initialized", direction);
|
|
||||||
|
|
||||||
var timer = 0;
|
var timer = 0;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// Warp Doors
|
// Warp Doors
|
||||||
function main() {
|
function main() {
|
||||||
console.log("Warp Door %s Initialized", Self.Title);
|
|
||||||
|
|
||||||
Self.SetHitbox(0, 0, 34, 76);
|
Self.SetHitbox(0, 0, 34, 76);
|
||||||
|
|
||||||
// Are we a blue or orange door? Regular warp door will be 'none'
|
// Are we a blue or orange door? Regular warp door will be 'none'
|
||||||
|
@ -31,12 +29,18 @@ function main() {
|
||||||
spriteDefault = "door-1";
|
spriteDefault = "door-1";
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Warp %s: default=%s disabled=%+v color=%s isState=%+v state=%+v", Self.Title, spriteDefault, spriteDisabled, color, isStateDoor, state);
|
// Find our linked Warp Door.
|
||||||
|
var links = Self.GetLinks()
|
||||||
|
var linkedDoor = null;
|
||||||
|
for (var i = 0; i < links.length; i++) {
|
||||||
|
if (links[i].Title.indexOf("Warp Door") > -1) {
|
||||||
|
linkedDoor = links[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Subscribe to the global state-change if we are a state door.
|
// Subscribe to the global state-change if we are a state door.
|
||||||
if (isStateDoor) {
|
if (isStateDoor) {
|
||||||
Message.Subscribe("broadcast:state-change", function(newState) {
|
Message.Subscribe("broadcast:state-change", function(newState) {
|
||||||
console.log("Warp %s: received state to %+v", Self.Title, newState);
|
|
||||||
state = color === 'blue' ? !newState : newState;
|
state = color === 'blue' ? !newState : newState;
|
||||||
|
|
||||||
// Activate or deactivate the door.
|
// Activate or deactivate the door.
|
||||||
|
@ -44,38 +48,69 @@ function main() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: respond to a "Use" button instead of a Collide to open the door.
|
// The player Uses the door.
|
||||||
Events.OnCollide(function(e) {
|
var flashedCooldown = false; // "Locked Door" flashed message.
|
||||||
if (!e.Settled) {
|
Events.OnUse(function(e) {
|
||||||
|
if (animating) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animating || collide) {
|
// Doors without linked exits are not usable.
|
||||||
|
if (linkedDoor === null) {
|
||||||
|
if (!flashedCooldown) {
|
||||||
|
Flash("This door is locked.");
|
||||||
|
flashedCooldown = true;
|
||||||
|
setTimeout(function() {
|
||||||
|
flashedCooldown = false;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only players can use doors for now.
|
// Only players can use doors for now.
|
||||||
if (e.Actor.IsPlayer() && e.InHitbox) {
|
if (e.Actor.IsPlayer()) {
|
||||||
if (isStateDoor && !state) {
|
if (isStateDoor && !state) {
|
||||||
// The state door is inactive (dotted outline).
|
// The state door is inactive (dotted outline).
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Freeze the player.
|
||||||
|
e.Actor.Freeze()
|
||||||
|
|
||||||
// Play the open and close animation.
|
// Play the open and close animation.
|
||||||
animating = true;
|
animating = true;
|
||||||
collide = true;
|
|
||||||
Self.PlayAnimation("open", function() {
|
Self.PlayAnimation("open", function() {
|
||||||
e.Actor.Hide()
|
e.Actor.Hide()
|
||||||
Self.PlayAnimation("close", function() {
|
Self.PlayAnimation("close", function() {
|
||||||
Self.ShowLayerNamed(isStateDoor && !state ? spriteDisabled : spriteDefault);
|
Self.ShowLayerNamed(isStateDoor && !state ? spriteDisabled : spriteDefault);
|
||||||
e.Actor.Show()
|
|
||||||
animating = false;
|
animating = false;
|
||||||
|
|
||||||
|
// Teleport the player to the linked door. Inform the target
|
||||||
|
// door of the arrival of the player so it doesn't trigger
|
||||||
|
// to send the player back here again on a loop.
|
||||||
|
if (linkedDoor !== null) {
|
||||||
|
Message.Publish("warp-door:incoming", e.Actor);
|
||||||
|
e.Actor.MoveTo(linkedDoor.Position());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Events.OnLeave(function(e) {
|
// Respond to incoming warp events.
|
||||||
collide = false;
|
Message.Subscribe("warp-door:incoming", function(player) {
|
||||||
|
animating = true;
|
||||||
|
player.Unfreeze();
|
||||||
|
Self.PlayAnimation("open", function() {
|
||||||
|
player.Show();
|
||||||
|
Self.PlayAnimation("close", function() {
|
||||||
|
animating = false;
|
||||||
|
|
||||||
|
// If the receiving door was a State Door, fix its state.
|
||||||
|
if (isStateDoor) {
|
||||||
|
Self.ShowLayerNamed(state ? spriteDefault : spriteDisabled);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,6 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI {
|
||||||
// Preload pop-up windows before they're needed.
|
// Preload pop-up windows before they're needed.
|
||||||
u.SetupPopups(d)
|
u.SetupPopups(d)
|
||||||
|
|
||||||
log.Error("menu size: %s", u.MenuBar.Rect())
|
|
||||||
u.screen.Pack(u.MenuBar, ui.Pack{
|
u.screen.Pack(u.MenuBar, ui.Pack{
|
||||||
Side: ui.N,
|
Side: ui.N,
|
||||||
FillX: true,
|
FillX: true,
|
||||||
|
@ -676,7 +675,6 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
|
||||||
|
|
||||||
menu.Supervise(u.Supervisor)
|
menu.Supervise(u.Supervisor)
|
||||||
menu.Compute(d.Engine)
|
menu.Compute(d.Engine)
|
||||||
log.Error("Setup MenuBar: %s\n", menu.Size())
|
|
||||||
|
|
||||||
return menu
|
return menu
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,3 +106,33 @@ func EraserTool(ev *event.State) bool {
|
||||||
func DoodadDropper(ev *event.State) bool {
|
func DoodadDropper(ev *event.State) bool {
|
||||||
return ev.KeyDown("d")
|
return ev.KeyDown("d")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shift key.
|
||||||
|
func Shift(ev *event.State) bool {
|
||||||
|
return ev.Shift
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left arrow.
|
||||||
|
func Left(ev *event.State) bool {
|
||||||
|
return ev.Left || ev.KeyDown("a")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right arrow.
|
||||||
|
func Right(ev *event.State) bool {
|
||||||
|
return ev.Right || ev.KeyDown("d")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Up arrow.
|
||||||
|
func Up(ev *event.State) bool {
|
||||||
|
return ev.Up || ev.KeyDown("w")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Down arrow.
|
||||||
|
func Down(ev *event.State) bool {
|
||||||
|
return ev.Down || ev.KeyDown("s")
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Use" button.
|
||||||
|
func Use(ev *event.State) bool {
|
||||||
|
return ev.Space || ev.KeyDown("q")
|
||||||
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ func LoadFile(filename string) (*Level, error) {
|
||||||
|
|
||||||
// Do we have the file in bindata?
|
// Do we have the file in bindata?
|
||||||
if jsonData, err := bindata.Asset(filename); err == nil {
|
if jsonData, err := bindata.Asset(filename); err == nil {
|
||||||
log.Info("loaded from embedded bindata")
|
log.Debug("Level %s: loaded from embedded bindata", filename)
|
||||||
return FromJSON(filename, jsonData)
|
return FromJSON(filename, jsonData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -471,30 +471,30 @@ func (s *PlayScene) movePlayer(ev *event.State) {
|
||||||
velocity.Y = 0
|
velocity.Y = 0
|
||||||
|
|
||||||
// Shift to slow your roll to 1 pixel per tick.
|
// Shift to slow your roll to 1 pixel per tick.
|
||||||
if ev.Shift {
|
if keybind.Shift(ev) {
|
||||||
playerSpeed = 1
|
playerSpeed = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if ev.Left {
|
if keybind.Left(ev) {
|
||||||
velocity.X = -playerSpeed
|
velocity.X = -playerSpeed
|
||||||
} else if ev.Right {
|
} else if keybind.Right(ev) {
|
||||||
velocity.X = playerSpeed
|
velocity.X = playerSpeed
|
||||||
}
|
}
|
||||||
if ev.Up {
|
if keybind.Up(ev) {
|
||||||
velocity.Y = -playerSpeed
|
velocity.Y = -playerSpeed
|
||||||
} else if ev.Down {
|
} else if keybind.Down(ev) {
|
||||||
velocity.Y = playerSpeed
|
velocity.Y = playerSpeed
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Moving left or right.
|
// Moving left or right.
|
||||||
if ev.Left {
|
if keybind.Left(ev) {
|
||||||
direction = -1
|
direction = -1
|
||||||
} else if ev.Right {
|
} else if keybind.Right(ev) {
|
||||||
direction = 1
|
direction = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Up button to signal they want to jump.
|
// Up button to signal they want to jump.
|
||||||
if ev.Up && (s.Player.Grounded() || s.playerJumpCounter >= 0) {
|
if keybind.Up(ev) && (s.Player.Grounded() || s.playerJumpCounter >= 0) {
|
||||||
jumping = true
|
jumping = true
|
||||||
|
|
||||||
if s.Player.Grounded() {
|
if s.Player.Grounded() {
|
||||||
|
@ -533,8 +533,18 @@ func (s *PlayScene) movePlayer(ev *event.State) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move the player unless frozen.
|
||||||
|
// TODO: if Y=0 then gravity fails, but not doing this allows the
|
||||||
|
// player to jump while frozen. Not a HUGE deal right now as only Warp Doors
|
||||||
|
// freeze the player currently but do address this later.
|
||||||
|
if s.Player.IsFrozen() {
|
||||||
|
velocity.X = 0
|
||||||
|
}
|
||||||
s.Player.SetVelocity(velocity)
|
s.Player.SetVelocity(velocity)
|
||||||
|
|
||||||
|
// If the "Use" key is pressed, set an actor flag on the player.
|
||||||
|
s.Player.SetUsing(keybind.Use(ev))
|
||||||
|
|
||||||
s.scripting.To(s.Player.ID()).Events.RunKeypress(ev)
|
s.scripting.To(s.Player.ID()).Events.RunKeypress(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ const (
|
||||||
CollideEvent = "OnCollide" // another doodad collides with us
|
CollideEvent = "OnCollide" // another doodad collides with us
|
||||||
EnterEvent = "OnEnter" // a doodad is fully inside us
|
EnterEvent = "OnEnter" // a doodad is fully inside us
|
||||||
LeaveEvent = "OnLeave" // a doodad no longer collides with us
|
LeaveEvent = "OnLeave" // a doodad no longer collides with us
|
||||||
|
UseEvent = "OnUse" // player pressed the Use key while touching us
|
||||||
|
|
||||||
// Controllable (player character) doodad events
|
// Controllable (player character) doodad events
|
||||||
KeypressEvent = "OnKeypress" // i.e. arrow keys
|
KeypressEvent = "OnKeypress" // i.e. arrow keys
|
||||||
|
@ -46,6 +47,16 @@ func (e *Events) RunCollide(v interface{}) error {
|
||||||
return e.run(CollideEvent, v)
|
return e.run(CollideEvent, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnUse fires when another actor collides with yours.
|
||||||
|
func (e *Events) OnUse(call otto.FunctionCall) otto.Value {
|
||||||
|
return e.register(UseEvent, call.Argument(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunUse invokes the OnUse handler function.
|
||||||
|
func (e *Events) RunUse(v interface{}) error {
|
||||||
|
return e.run(UseEvent, v)
|
||||||
|
}
|
||||||
|
|
||||||
// OnLeave fires when another actor stops colliding with yours.
|
// OnLeave fires when another actor stops colliding with yours.
|
||||||
func (e *Events) OnLeave(call otto.FunctionCall) otto.Value {
|
func (e *Events) OnLeave(call otto.FunctionCall) otto.Value {
|
||||||
return e.register(LeaveEvent, call.Argument(0))
|
return e.register(LeaveEvent, call.Argument(0))
|
||||||
|
|
|
@ -93,9 +93,9 @@ func (s *Supervisor) To(name string) *VM {
|
||||||
|
|
||||||
// TODO: put this log back in, but add PLAYER script so it doesn't spam
|
// TODO: put this log back in, but add PLAYER script so it doesn't spam
|
||||||
// the console for missing PLAYER.
|
// the console for missing PLAYER.
|
||||||
// log.Error("scripting.Supervisor.To(%s): no such VM but returning blank VM",
|
log.Error("scripting.Supervisor.To(%s): no such VM but returning blank VM",
|
||||||
// name,
|
name,
|
||||||
// )
|
)
|
||||||
return NewVM(name)
|
return NewVM(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,19 +25,20 @@ import (
|
||||||
// as defined in the map: its spawn coordinate and configuration.
|
// as defined in the map: its spawn coordinate and configuration.
|
||||||
// - A uix.Canvas that can present the actor's graphics to the screen.
|
// - A uix.Canvas that can present the actor's graphics to the screen.
|
||||||
type Actor struct {
|
type Actor struct {
|
||||||
id string
|
|
||||||
Drawing *doodads.Drawing
|
Drawing *doodads.Drawing
|
||||||
Actor *level.Actor
|
Actor *level.Actor
|
||||||
Canvas *Canvas
|
Canvas *Canvas
|
||||||
|
|
||||||
activeLayer int // active drawing frame for display
|
activeLayer int // active drawing frame for display
|
||||||
flagDestroy bool // flag the actor for destruction
|
flagDestroy bool // flag the actor for destruction
|
||||||
|
flagUsing bool // flag that the (player) has pressed the Use key.
|
||||||
|
|
||||||
// Actor runtime variables.
|
// Actor runtime variables.
|
||||||
hasGravity bool
|
hasGravity bool
|
||||||
isMobile bool // Mobile character, such as the player or an enemy
|
isMobile bool // Mobile character, such as the player or an enemy
|
||||||
noclip bool // Disable collision detection
|
noclip bool // Disable collision detection
|
||||||
hidden bool // invisible, via Hide() and Show()
|
hidden bool // invisible, via Hide() and Show()
|
||||||
|
frozen bool // Frozen, via Freeze() and Unfreeze()
|
||||||
hitbox render.Rect
|
hitbox render.Rect
|
||||||
inventory map[string]int // item inventory. doodad name -> quantity, 0 for key item.
|
inventory map[string]int // item inventory. doodad name -> quantity, 0 for key item.
|
||||||
data map[string]string // arbitrary key/value store. DEPRECATED ??
|
data map[string]string // arbitrary key/value store. DEPRECATED ??
|
||||||
|
@ -174,6 +175,28 @@ func (a *Actor) Show() {
|
||||||
a.hidden = false
|
a.hidden = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Freeze an actor. For the player character, this means arrow key inputs
|
||||||
|
// will stop moving the actor.
|
||||||
|
func (a *Actor) Freeze() {
|
||||||
|
a.frozen = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unfreeze an actor.
|
||||||
|
func (a *Actor) Unfreeze() {
|
||||||
|
a.frozen = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFrozen returns true if the actor is frozen.
|
||||||
|
func (a *Actor) IsFrozen() bool {
|
||||||
|
return a.frozen
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUsing enables the "Use Key" flag, mainly for the player character to activate
|
||||||
|
// certain doodads in the level.
|
||||||
|
func (a *Actor) SetUsing(v bool) {
|
||||||
|
a.flagUsing = v
|
||||||
|
}
|
||||||
|
|
||||||
// SetNoclip sets the noclip setting for an actor. If true, the actor can
|
// SetNoclip sets the noclip setting for an actor. If true, the actor can
|
||||||
// clip through level geometry.
|
// clip through level geometry.
|
||||||
func (a *Actor) SetNoclip(v bool) {
|
func (a *Actor) SetNoclip(v bool) {
|
||||||
|
|
|
@ -276,6 +276,16 @@ func (w *Canvas) loopActorCollision() error {
|
||||||
}); err != nil && err != scripting.ErrReturnFalse {
|
}); err != nil && err != scripting.ErrReturnFalse {
|
||||||
log.Error("VM(%s).RunCollide: %s", a.ID(), err.Error())
|
log.Error("VM(%s).RunCollide: %s", a.ID(), err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the (player) is pressing the Use key, call the colliding
|
||||||
|
// actor's OnUse event.
|
||||||
|
if b.flagUsing {
|
||||||
|
if err := w.scripting.To(a.ID()).Events.RunUse(&UseEvent{
|
||||||
|
Actor: b,
|
||||||
|
}); err != nil {
|
||||||
|
log.Error("VM(%s).RunUse: %s", a.ID(), err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,3 +9,8 @@ type CollideEvent struct {
|
||||||
InHitbox bool // If the two elected hitboxes are overlapping
|
InHitbox bool // If the two elected hitboxes are overlapping
|
||||||
Settled bool // Movement phase finished, actor script can fire actions
|
Settled bool // Movement phase finished, actor script can fire actions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UseEvent holds data sent to an actor's OnUse handler.
|
||||||
|
type UseEvent struct {
|
||||||
|
Actor *Actor
|
||||||
|
}
|
||||||
|
|
|
@ -57,26 +57,7 @@ func (w *Canvas) InstallScripts() error {
|
||||||
vm := w.scripting.To(actor.ID())
|
vm := w.scripting.To(actor.ID())
|
||||||
|
|
||||||
// Security: expose a selective API to the actor to the JS engine.
|
// Security: expose a selective API to the actor to the JS engine.
|
||||||
vm.Self = map[string]interface{}{
|
vm.Self = w.MakeSelfAPI(actor)
|
||||||
"Filename": actor.Doodad().Filename,
|
|
||||||
"Title": actor.Doodad().Title,
|
|
||||||
|
|
||||||
// functions
|
|
||||||
"ID": actor.ID,
|
|
||||||
"GetTag": actor.Doodad().Tag,
|
|
||||||
"Position": actor.Position,
|
|
||||||
"SetHitbox": actor.SetHitbox,
|
|
||||||
"SetVelocity": actor.SetVelocity,
|
|
||||||
"SetMobile": actor.SetMobile,
|
|
||||||
"SetGravity": actor.SetGravity,
|
|
||||||
"AddAnimation": actor.AddAnimation,
|
|
||||||
"IsAnimating": actor.IsAnimating,
|
|
||||||
"PlayAnimation": actor.PlayAnimation,
|
|
||||||
"StopAnimation": actor.StopAnimation,
|
|
||||||
"ShowLayer": actor.ShowLayer,
|
|
||||||
"ShowLayerNamed": actor.ShowLayerNamed,
|
|
||||||
"Destroy": actor.Destroy,
|
|
||||||
}
|
|
||||||
vm.Set("Self", vm.Self)
|
vm.Set("Self", vm.Self)
|
||||||
|
|
||||||
if _, err := vm.Run(actor.Doodad().Script); err != nil {
|
if _, err := vm.Run(actor.Doodad().Script); err != nil {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package uix
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/drawtool"
|
"git.kirsle.net/apps/doodle/pkg/drawtool"
|
||||||
"git.kirsle.net/apps/doodle/pkg/shmem"
|
"git.kirsle.net/apps/doodle/pkg/shmem"
|
||||||
|
@ -34,3 +35,34 @@ func (w *Canvas) LinkAdd(a *Actor) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLinkedActors returns the live Actor instances (Play Mode) which are linked
|
||||||
|
// to the live actor given.
|
||||||
|
func (w *Canvas) GetLinkedActors(a *Actor) []*Actor {
|
||||||
|
// Identify the linked actor UUIDs from the level file.
|
||||||
|
linkedIDs := map[string]interface{}{}
|
||||||
|
matching := map[string]*Actor{}
|
||||||
|
for _, id := range a.Actor.Links {
|
||||||
|
linkedIDs[id] = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find live instances of these actors.
|
||||||
|
for _, live := range w.actors {
|
||||||
|
if _, ok := linkedIDs[live.ID()]; ok {
|
||||||
|
matching[live.ID()] = live
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort them deterministically and return.
|
||||||
|
keys := []string{}
|
||||||
|
for key, _ := range matching {
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
result := []*Actor{}
|
||||||
|
for _, key := range keys {
|
||||||
|
result = append(result, matching[key])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
35
pkg/uix/scripting.go
Normal file
35
pkg/uix/scripting.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package uix
|
||||||
|
|
||||||
|
// Functions relating to the Doodad JavaScript API for Canvas Actors.
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
"GetTag": actor.Doodad().Tag,
|
||||||
|
"Position": actor.Position,
|
||||||
|
"SetHitbox": actor.SetHitbox,
|
||||||
|
"SetVelocity": actor.SetVelocity,
|
||||||
|
"SetMobile": actor.SetMobile,
|
||||||
|
"SetGravity": actor.SetGravity,
|
||||||
|
"AddAnimation": actor.AddAnimation,
|
||||||
|
"IsAnimating": actor.IsAnimating,
|
||||||
|
"PlayAnimation": actor.PlayAnimation,
|
||||||
|
"StopAnimation": actor.StopAnimation,
|
||||||
|
"ShowLayer": actor.ShowLayer,
|
||||||
|
"ShowLayerNamed": actor.ShowLayerNamed,
|
||||||
|
"Destroy": actor.Destroy,
|
||||||
|
"GetLinks": func() []map[string]interface{} {
|
||||||
|
var result = []map[string]interface{}{}
|
||||||
|
for _, linked := range w.GetLinkedActors(actor) {
|
||||||
|
result = append(result, w.MakeSelfAPI(linked))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
"git.kirsle.net/apps/doodle/pkg/doodads"
|
"git.kirsle.net/apps/doodle/pkg/doodads"
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/shmem"
|
"git.kirsle.net/apps/doodle/pkg/shmem"
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
"git.kirsle.net/go/ui"
|
"git.kirsle.net/go/ui"
|
||||||
|
@ -54,7 +53,6 @@ func NewLayerWindow(config Layers) *ui.Window {
|
||||||
)
|
)
|
||||||
|
|
||||||
config.activeLayer = fmt.Sprintf("%d", config.ActiveLayer)
|
config.activeLayer = fmt.Sprintf("%d", config.ActiveLayer)
|
||||||
log.Warn("config.activeLayer=%s", config.activeLayer)
|
|
||||||
|
|
||||||
window := ui.NewWindow(title)
|
window := ui.NewWindow(title)
|
||||||
window.SetButtons(ui.CloseButton)
|
window.SetButtons(ui.CloseButton)
|
||||||
|
@ -71,8 +69,6 @@ func NewLayerWindow(config Layers) *ui.Window {
|
||||||
Expand: true,
|
Expand: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Info("SETUP PALETTE WINDOW")
|
|
||||||
|
|
||||||
// Draw the header row.
|
// Draw the header row.
|
||||||
headers := []struct {
|
headers := []struct {
|
||||||
Name string
|
Name string
|
||||||
|
@ -143,7 +139,6 @@ func NewLayerWindow(config Layers) *ui.Window {
|
||||||
})
|
})
|
||||||
btnName.Handle(ui.Click, func(ed ui.EventData) error {
|
btnName.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
shmem.Prompt("New layer name ["+doodad.Layers[i].Name+"]: ", func(answer string) {
|
shmem.Prompt("New layer name ["+doodad.Layers[i].Name+"]: ", func(answer string) {
|
||||||
log.Warn("Answer: %s", answer)
|
|
||||||
if answer != "" {
|
if answer != "" {
|
||||||
doodad.Layers[i].Name = answer
|
doodad.Layers[i].Name = answer
|
||||||
if config.OnChange != nil {
|
if config.OnChange != nil {
|
||||||
|
@ -220,7 +215,6 @@ func NewLayerWindow(config Layers) *ui.Window {
|
||||||
Font: balance.MenuFont,
|
Font: balance.MenuFont,
|
||||||
OnChange: func(newPage, perPage int) {
|
OnChange: func(newPage, perPage int) {
|
||||||
page = newPage
|
page = newPage
|
||||||
log.Info("Page: %d, %d", page, perPage)
|
|
||||||
|
|
||||||
// Re-evaluate which rows are shown/hidden for this page.
|
// Re-evaluate which rows are shown/hidden for this page.
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
"git.kirsle.net/apps/doodle/pkg/level"
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/userdir"
|
"git.kirsle.net/apps/doodle/pkg/userdir"
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
"git.kirsle.net/go/ui"
|
"git.kirsle.net/go/ui"
|
||||||
|
@ -74,7 +73,6 @@ func NewOpenLevelEditor(config OpenLevelEditor) *ui.Window {
|
||||||
})
|
})
|
||||||
for i, lvl := range levels {
|
for i, lvl := range levels {
|
||||||
func(i int, lvl string) {
|
func(i int, lvl string) {
|
||||||
log.Info("Add file %s to row %s", lvl, lvlRow.Name)
|
|
||||||
btn := ui.NewButton("Level Btn", ui.NewLabel(ui.Label{
|
btn := ui.NewButton("Level Btn", ui.NewLabel(ui.Label{
|
||||||
Text: lvl,
|
Text: lvl,
|
||||||
Font: balance.MenuFont,
|
Font: balance.MenuFont,
|
||||||
|
@ -95,7 +93,6 @@ func NewOpenLevelEditor(config OpenLevelEditor) *ui.Window {
|
||||||
})
|
})
|
||||||
|
|
||||||
if i > 0 && (i+1)%4 == 0 {
|
if i > 0 && (i+1)%4 == 0 {
|
||||||
log.Warn("i=%d wrapped at mod 4", i)
|
|
||||||
lvlRow = ui.NewFrame(fmt.Sprintf("Level Row %d", i))
|
lvlRow = ui.NewFrame(fmt.Sprintf("Level Row %d", i))
|
||||||
frame.Pack(lvlRow, ui.Pack{
|
frame.Pack(lvlRow, ui.Pack{
|
||||||
Side: ui.N,
|
Side: ui.N,
|
||||||
|
|
|
@ -73,8 +73,6 @@ func NewPaletteEditor(config PaletteEditor) *ui.Window {
|
||||||
Expand: true,
|
Expand: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Info("SETUP PALETTE WINDOW")
|
|
||||||
|
|
||||||
// Draw the header row.
|
// Draw the header row.
|
||||||
headers := []struct {
|
headers := []struct {
|
||||||
Name string
|
Name string
|
||||||
|
|
Loading…
Reference in New Issue
Block a user