From a40cc0602ef3f13fea305a6b15639b58428cd76c Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Mon, 9 Aug 2021 22:42:22 -0700 Subject: [PATCH] Thief and Inventory APIs This commit adds the Thief character with starter graphics (no animations). The Thief walks back and forth and will steal items from other doodads, including the player. For singleton items that have no quantity, like the Colored Keys, the Thief will only steal one if he does not already have it. Quantitied items like the Small Key are always stolen. Flexibility in the playable character is introduced: Boy, Azulian, Bird, and Thief all respond to playable controls. There is not currently a method to enable these apart from modifying balance.PlayerCharacterDoodad at compile time. New and Changed Doodads * Thief: new doodad that walks back and forth and will steal items from other characters inventory. * Bird: has no inventory and cannot pick up items, unless player controlled. Its hitbox has also been fixed so it collides with floors correctly - not something normally seen in the Bird. * Boy: opts in to have inventory. * Keys (all): only gives themselves to actors having inventories. JavaScript API - New functions available * Self.IsPlayer() - returns if the current actor IS the player. * Self.SetInventory(bool) - doodads must opt-in to having an inventory. Keys should only give themselves to doodads having an inventory. * Self.HasInventory() bool * Self.AddItem(filename, qty) * Self.RemoveItem(filename, qty) * Self.HasItem(filename) * Self.Inventory() - returns map[string]int * Self.ClearInventory() * Self.OnLeave(func(e)) now receives a CollideEvent as parameter instead of the useless actor ID. Notably, e.Actor is the leaving actor and e.Settled is always true. Other Changes * Play Mode: if playing as a character which doesn't obey gravity, such as the bird, antigravity controls are enabled by default. If you `import antigravity` you can turn gravity back on. * Doodad collision scripts are no longer run in parallel goroutines. It made the Thief's job difficult trying to steal items in many threads simultaneously! --- dev-assets/doodads/azulian/azulian-red.js | 5 +- dev-assets/doodads/azulian/azulian.js | 3 +- dev-assets/doodads/bird/bird.js | 48 ++++++++-- dev-assets/doodads/boy/boy.js | 3 +- dev-assets/doodads/build.sh | 4 + dev-assets/doodads/doors/keys.js | 10 ++- dev-assets/doodads/thief/Makefile | 11 +++ dev-assets/doodads/thief/stand-left.png | Bin 0 -> 1520 bytes dev-assets/doodads/thief/stand-right.png | Bin 0 -> 1531 bytes dev-assets/doodads/thief/thief.js | 104 ++++++++++++++++++++++ 10 files changed, 175 insertions(+), 13 deletions(-) create mode 100644 dev-assets/doodads/thief/Makefile create mode 100644 dev-assets/doodads/thief/stand-left.png create mode 100644 dev-assets/doodads/thief/stand-right.png create mode 100644 dev-assets/doodads/thief/thief.js diff --git a/dev-assets/doodads/azulian/azulian-red.js b/dev-assets/doodads/azulian/azulian-red.js index 45f5881..f42d92d 100644 --- a/dev-assets/doodads/azulian/azulian-red.js +++ b/dev-assets/doodads/azulian/azulian-red.js @@ -7,6 +7,7 @@ function main() { Self.SetHitbox(0, 0, 32, 32) Self.SetMobile(true); + Self.SetInventory(true); Self.SetGravity(true); Self.AddAnimation("walk-left", 100, ["red-wl1", "red-wl2", "red-wl3", "red-wl4"]); Self.AddAnimation("walk-right", 100, ["red-wr1", "red-wr2", "red-wr3", "red-wr4"]); @@ -16,7 +17,7 @@ function main() { var sampleRate = 5; var lastSampledX = 0; - setInterval(function() { + setInterval(function () { if (sampleTick % sampleRate === 0) { var curX = Self.Position().X; var delta = Math.abs(curX - lastSampledX); @@ -33,7 +34,7 @@ function main() { Self.SetVelocity(Vector(Vx, 0.0)); if (!Self.IsAnimating()) { - Self.PlayAnimation("walk-"+direction, null); + Self.PlayAnimation("walk-" + direction, null); } }, 100); } diff --git a/dev-assets/doodads/azulian/azulian.js b/dev-assets/doodads/azulian/azulian.js index a01881c..3aa7637 100644 --- a/dev-assets/doodads/azulian/azulian.js +++ b/dev-assets/doodads/azulian/azulian.js @@ -9,11 +9,12 @@ function main() { Self.SetMobile(true); Self.SetGravity(true); + Self.SetInventory(true); Self.SetHitbox(7, 4, 17, 28); Self.AddAnimation("walk-left", 100, ["blu-wl1", "blu-wl2", "blu-wl3", "blu-wl4"]); Self.AddAnimation("walk-right", 100, ["blu-wr1", "blu-wr2", "blu-wr3", "blu-wr4"]); - Events.OnKeypress(function(ev) { + Events.OnKeypress(function (ev) { Vx = 0; Vy = 0; diff --git a/dev-assets/doodads/bird/bird.js b/dev-assets/doodads/bird/bird.js index d7bb2a7..e6d38c8 100644 --- a/dev-assets/doodads/bird/bird.js +++ b/dev-assets/doodads/bird/bird.js @@ -1,4 +1,5 @@ -// Red bird mob. +// Bird + function main() { var speed = 4; var Vx = Vy = 0; @@ -13,11 +14,16 @@ function main() { Self.SetMobile(true); Self.SetGravity(false); - Self.SetHitbox(0, 10, 46, 32); + Self.SetHitbox(0, 0, 46, 32); Self.AddAnimation("fly-left", 100, ["left-1", "left-2"]); Self.AddAnimation("fly-right", 100, ["right-1", "right-2"]); - Events.OnCollide(function(e) { + // Player Character controls? + if (Self.IsPlayer()) { + return player(); + } + + Events.OnCollide(function (e) { if (e.Actor.IsMobile() && e.InHitbox) { return false; } @@ -29,7 +35,7 @@ function main() { var lastSampledX = 0; var lastSampledY = 0; - setInterval(function() { + setInterval(function () { if (sampleTick % sampleRate === 0) { var curX = Self.Position().X; var delta = Math.abs(curX - lastSampledX); @@ -46,7 +52,39 @@ function main() { Self.SetVelocity(Vector(Vx, 0.0)); if (!Self.IsAnimating()) { - Self.PlayAnimation("fly-"+direction, null); + Self.PlayAnimation("fly-" + direction, null); } }, 100); } + +// If under control of the player character. +function player() { + Self.SetInventory(true); + Events.OnKeypress(function (ev) { + Vx = 0; + Vy = 0; + + if (ev.Up) { + Vy = -playerSpeed; + } else if (ev.Down) { + Vy = playerSpeed; + } + + if (ev.Right) { + if (!Self.IsAnimating()) { + Self.PlayAnimation("fly-right", null); + } + Vx = playerSpeed; + } else if (ev.Left) { + if (!Self.IsAnimating()) { + Self.PlayAnimation("fly-left", null); + } + Vx = -playerSpeed; + } else { + Self.StopAnimation(); + animating = false; + } + + Self.SetVelocity(Vector(Vx, Vy)); + }) +} \ No newline at end of file diff --git a/dev-assets/doodads/boy/boy.js b/dev-assets/doodads/boy/boy.js index 362a6c0..02f877b 100644 --- a/dev-assets/doodads/boy/boy.js +++ b/dev-assets/doodads/boy/boy.js @@ -8,12 +8,13 @@ function main() { var animFrame = animStart; Self.SetMobile(true); + Self.SetInventory(true); Self.SetGravity(true); Self.SetHitbox(0, 0, 32, 52); Self.AddAnimation("walk-left", 200, ["stand-left", "walk-left-1", "walk-left-2", "walk-left-3", "walk-left-2", "walk-left-1"]); Self.AddAnimation("walk-right", 200, ["stand-right", "walk-right-1", "walk-right-2", "walk-right-3", "walk-right-2", "walk-right-1"]); - Events.OnKeypress(function(ev) { + Events.OnKeypress(function (ev) { Vx = 0; Vy = 0; diff --git a/dev-assets/doodads/build.sh b/dev-assets/doodads/build.sh index 5597a19..9c99564 100755 --- a/dev-assets/doodads/build.sh +++ b/dev-assets/doodads/build.sh @@ -12,6 +12,10 @@ boy() { cd boy/ make cd .. + + cd thief/ + make + cd .. } buttons() { diff --git a/dev-assets/doodads/doors/keys.js b/dev-assets/doodads/doors/keys.js index 593b871..469a158 100644 --- a/dev-assets/doodads/doors/keys.js +++ b/dev-assets/doodads/doors/keys.js @@ -2,11 +2,13 @@ function main() { var color = Self.GetTag("color"); var quantity = color === "small" ? 1 : 0; - Events.OnCollide(function(e) { + Events.OnCollide(function (e) { if (e.Settled) { - Sound.Play("item-get.wav") - e.Actor.AddItem(Self.Filename, quantity); - Self.Destroy(); + if (e.Actor.HasInventory()) { + Sound.Play("item-get.wav") + e.Actor.AddItem(Self.Filename, quantity); + Self.Destroy(); + } } }) } diff --git a/dev-assets/doodads/thief/Makefile b/dev-assets/doodads/thief/Makefile new file mode 100644 index 0000000..fc6b00c --- /dev/null +++ b/dev-assets/doodads/thief/Makefile @@ -0,0 +1,11 @@ +ALL: build + +.PHONY: build +build: + doodad convert -t "Thief" stand-right.png stand-left.png \ + thief.doodad + doodad install-script thief.js thief.doodad + + doodad edit-doodad --tag "category=creatures" thief.doodad + + cp *.doodad ../../../assets/doodads/ \ No newline at end of file diff --git a/dev-assets/doodads/thief/stand-left.png b/dev-assets/doodads/thief/stand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..9e58a9876cdbe32025faebd6929d62cb2ed764ba GIT binary patch literal 1520 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 literal 0 HcmV?d00001 diff --git a/dev-assets/doodads/thief/thief.js b/dev-assets/doodads/thief/thief.js new file mode 100644 index 0000000..e7a86dc --- /dev/null +++ b/dev-assets/doodads/thief/thief.js @@ -0,0 +1,104 @@ +// Thief + +function main() { + Self.SetMobile(true); + Self.SetGravity(true); + Self.SetInventory(true); + Self.SetHitbox(0, 0, 32, 58); + Self.AddAnimation("walk-left", 200, ["stand-left"]); //, "walk-left-1", "walk-left-2", "walk-left-3", "walk-left-2", "walk-left-1"]); + Self.AddAnimation("walk-right", 200, ["stand-right"]); //, "walk-right-1", "walk-right-2", "walk-right-3", "walk-right-2", "walk-right-1"]); + + // Controlled by the player character? + if (Self.IsPlayer()) { + return playable(); + } + return ai(); +} + +// Enemy Doodad AI. +function ai() { + // Walks back and forth. + var Vx = Vy = 0.0, + playerSpeed = 4, + direction = "right", + lastSampledX = 0, + sampleTick = 0, + sampleRate = 2, + stolenItems = {}; // map item->qty + + setInterval(function () { + if (sampleTick % sampleRate === 0) { + var curX = Self.Position().X, + delta = Math.abs(curX - lastSampledX); + if (delta < 5) { + direction = direction === "right" ? "left" : "right"; + } + lastSampledX = curX; + } + sampleTick++; + + Vx = parseFloat(playerSpeed * (direction === "left" ? -1 : 1)); + Self.SetVelocity(Vector(Vx, Vy)); + + Self.StopAnimation(); + Self.PlayAnimation("walk-" + direction, null); + }, 100); + + // Steals your items. + Events.OnCollide(function (e) { + if (!e.Settled) { + return; + } + + // Steal inventory + var stolen = 0; + if (e.Actor.HasInventory()) { + var myInventory = Self.Inventory(), + theirInventory = e.Actor.Inventory(); + + for (var key in theirInventory) { + if (!theirInventory.hasOwnProperty(key)) { + continue; + } + + var value = theirInventory[key]; + if (value > 0 || myInventory[key] === undefined) { + e.Actor.RemoveItem(key, value); + Self.AddItem(key, value); + stolenItems[key] = value; + stolen += (value === 0 ? 1 : value); + } + } + + // Notify the player if it was them. + if (e.Actor.IsPlayer() && stolen > 0) { + Flash("Watch out for thieves! %d item%s stolen!", parseInt(stolen), stolen === 1 ? ' was' : 's were'); + } + } + }); +} + +// If under control of the player character. +function playable() { + Events.OnKeypress(function (ev) { + Vx = 0; + Vy = 0; + + if (ev.Right) { + if (!Self.IsAnimating()) { + Self.PlayAnimation("walk-right", null); + } + Vx = playerSpeed; + } else if (ev.Left) { + if (!Self.IsAnimating()) { + Self.PlayAnimation("walk-left", null); + } + Vx = -playerSpeed; + } else { + Self.StopAnimation(); + animating = false; + } + + // Self.SetVelocity(Point(Vx, Vy)); + }) +} \ No newline at end of file