White Azulian, Respawn invincibility timer
* Respawning from a checkpoint grants 3 seconds of immunity in case enemies are spawn camping. * Add the white Azulian as an even faster and harder enemy than the red Azulian: twice as fast, jumps higher, and can detect the player from further away.
|
@ -14,6 +14,11 @@ build:
|
||||||
doodad edit-doodad --tag "color=red" azu-red.doodad
|
doodad edit-doodad --tag "color=red" azu-red.doodad
|
||||||
doodad install-script azulian.js azu-red.doodad
|
doodad install-script azulian.js azu-red.doodad
|
||||||
|
|
||||||
|
doodad convert -t "White Azulian" white-front.png white-back.png \
|
||||||
|
white-wr{1,2,3,4}.png white-wl{1,2,3,4}.png azu-white.doodad
|
||||||
|
doodad edit-doodad --tag "color=white" azu-white.doodad
|
||||||
|
doodad install-script azulian.js azu-white.doodad
|
||||||
|
|
||||||
# Tag the category for these doodads
|
# Tag the category for these doodads
|
||||||
for i in *.doodad; do\
|
for i in *.doodad; do\
|
||||||
doodad edit-doodad --tag "category=creatures" $${i};\
|
doodad edit-doodad --tag "category=creatures" $${i};\
|
||||||
|
|
|
@ -9,9 +9,17 @@ var playerSpeed = color === 'blue' ? 2 : 4,
|
||||||
direction = "right",
|
direction = "right",
|
||||||
lastDirection = "right";
|
lastDirection = "right";
|
||||||
|
|
||||||
|
// white Azulian is faster yet than the red
|
||||||
|
if (color === 'white') {
|
||||||
|
aggroX = 1000;
|
||||||
|
aggroY = 400;
|
||||||
|
playerSpeed = 8;
|
||||||
|
jumpSpeed = 16;
|
||||||
|
}
|
||||||
|
|
||||||
function setupAnimations(color) {
|
function setupAnimations(color) {
|
||||||
let left = color === 'blue' ? 'blu-wl' : 'red-wl',
|
let left = color === 'blue' ? 'blu-wl' : color+'-wl',
|
||||||
right = color === 'blue' ? 'blu-wr' : 'red-wr',
|
right = color === 'blue' ? 'blu-wr' : color+'-wr',
|
||||||
leftFrames = [left + '1', left + '2', left + '3', left + '4'],
|
leftFrames = [left + '1', left + '2', left + '3', left + '4'],
|
||||||
rightFrames = [right + '1', right + '2', right + '3', right + '4'];
|
rightFrames = [right + '1', right + '2', right + '3', right + '4'];
|
||||||
|
|
||||||
|
|
BIN
dev-assets/doodads/azulian/white-back.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
dev-assets/doodads/azulian/white-front.png
Normal file
After Width: | Height: | Size: 1004 B |
BIN
dev-assets/doodads/azulian/white-wl1.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
dev-assets/doodads/azulian/white-wl2.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
dev-assets/doodads/azulian/white-wl3.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
dev-assets/doodads/azulian/white-wl4.png
Normal file
After Width: | Height: | Size: 1002 B |
BIN
dev-assets/doodads/azulian/white-wr1.png
Normal file
After Width: | Height: | Size: 994 B |
BIN
dev-assets/doodads/azulian/white-wr2.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
dev-assets/doodads/azulian/white-wr3.png
Normal file
After Width: | Height: | Size: 985 B |
BIN
dev-assets/doodads/azulian/white-wr4.png
Normal file
After Width: | Height: | Size: 999 B |
|
@ -4,13 +4,13 @@ let speed = 4,
|
||||||
Vx = Vy = 0,
|
Vx = Vy = 0,
|
||||||
altitude = Self.Position().Y; // original height in the level
|
altitude = Self.Position().Y; // original height in the level
|
||||||
|
|
||||||
let direction = "left",
|
let direction = "left",
|
||||||
lastDirection = "left";
|
lastDirection = "left";
|
||||||
let states = {
|
let states = {
|
||||||
flying: 0,
|
flying: 0,
|
||||||
diving: 1,
|
diving: 1,
|
||||||
};
|
};
|
||||||
let state = states.flying;
|
let state = states.flying;
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
Self.SetMobile(true);
|
Self.SetMobile(true);
|
||||||
|
@ -106,6 +106,8 @@ function main() {
|
||||||
// A.I. subroutine: scan for the player character.
|
// A.I. subroutine: scan for the player character.
|
||||||
// The bird scans in a 45 degree angle downwards, if the
|
// The bird scans in a 45 degree angle downwards, if the
|
||||||
// player is seen nearby in that scan it will begin a dive.
|
// player is seen nearby in that scan it will begin a dive.
|
||||||
|
// It's not hostile towards characters that can fly (having
|
||||||
|
// no gravity).
|
||||||
function AI_ScanForPlayer() {
|
function AI_ScanForPlayer() {
|
||||||
let stepY = 12, // number of pixels to skip
|
let stepY = 12, // number of pixels to skip
|
||||||
stepX = stepY,
|
stepX = stepY,
|
||||||
|
@ -130,7 +132,7 @@ function AI_ScanForPlayer() {
|
||||||
scanX += stepX;
|
scanX += stepX;
|
||||||
scanY += stepY;
|
scanY += stepY;
|
||||||
for (let actor of Actors.At(Point(scanX, scanY))) {
|
for (let actor of Actors.At(Point(scanX, scanY))) {
|
||||||
if (actor.IsPlayer()) {
|
if (actor.IsPlayer() && actor.HasGravity()) {
|
||||||
state = states.diving;
|
state = states.diving;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,10 @@ var (
|
||||||
PlayModeIdleTimeout = 2200 * time.Millisecond
|
PlayModeIdleTimeout = 2200 * time.Millisecond
|
||||||
PlayModeAlphaStep = 8 // 0-255 alpha, steps per tick for fade in
|
PlayModeAlphaStep = 8 // 0-255 alpha, steps per tick for fade in
|
||||||
PlayModeAlphaMax = 220
|
PlayModeAlphaMax = 220
|
||||||
|
|
||||||
|
// Invulnerability time in seconds at respawn from checkpoint, in case
|
||||||
|
// enemies are spawn camping.
|
||||||
|
RespawnGodModeTimer = 3 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// Edit Mode Values
|
// Edit Mode Values
|
||||||
|
|
|
@ -70,6 +70,7 @@ type PlayScene struct {
|
||||||
antigravity bool // Cheat: disable player gravity
|
antigravity bool // Cheat: disable player gravity
|
||||||
noclip bool // Cheat: disable player clipping
|
noclip bool // Cheat: disable player clipping
|
||||||
godMode bool // Cheat: player can't die
|
godMode bool // Cheat: player can't die
|
||||||
|
godModeUntil time.Time // Invulnerability timer at respawn.
|
||||||
playerJumpCounter int // limit jump length
|
playerJumpCounter int // limit jump length
|
||||||
|
|
||||||
// Inventory HUD. Impl. in play_inventory.go
|
// Inventory HUD. Impl. in play_inventory.go
|
||||||
|
@ -404,6 +405,9 @@ func (s *PlayScene) SetCheckpoint(where render.Point) {
|
||||||
|
|
||||||
// RetryCheckpoint moves the player back to their last checkpoint.
|
// RetryCheckpoint moves the player back to their last checkpoint.
|
||||||
func (s *PlayScene) RetryCheckpoint() {
|
func (s *PlayScene) RetryCheckpoint() {
|
||||||
|
// Grant the player invulnerability for 5 seconds
|
||||||
|
s.godModeUntil = time.Now().Add(balance.RespawnGodModeTimer)
|
||||||
|
|
||||||
log.Info("Move player back to last checkpoint")
|
log.Info("Move player back to last checkpoint")
|
||||||
s.Player.MoveTo(s.lastCheckpoint)
|
s.Player.MoveTo(s.lastCheckpoint)
|
||||||
s.running = true
|
s.running = true
|
||||||
|
@ -421,11 +425,12 @@ func (s *PlayScene) BeatLevel() {
|
||||||
|
|
||||||
// FailLevel handles a level failure triggered by a doodad.
|
// FailLevel handles a level failure triggered by a doodad.
|
||||||
func (s *PlayScene) FailLevel(message string) {
|
func (s *PlayScene) FailLevel(message string) {
|
||||||
if s.godMode {
|
if s.godMode || s.godModeUntil.After(time.Now()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.SetImperfect()
|
s.SetImperfect()
|
||||||
s.d.FlashError(message)
|
s.d.FlashError(message)
|
||||||
|
|
||||||
s.ShowEndLevelModal(
|
s.ShowEndLevelModal(
|
||||||
false,
|
false,
|
||||||
"You've died!",
|
"You've died!",
|
||||||
|
|