Level Difficulty + UI Polish

Added a new level property: Difficulty

* An enum ranging from -1, 0, 1 (Peaceful, Normal, Hard)
* Default difficulty is Normal; pre-existing levels are Normal by
  default per the zero value.

Doodad scripts can read the difficulty via the new global variable
`Level.Difficulty` and some doodads have been updated:

* Azulians: on Peaceful they ignore all player characters, and on Hard
  they are in "hunt mode": infinite aggro radius and they're aggressive
  to all characters.
* Bird: on Peaceful they will not dive and attack any player character.

Other spit and polish:

* New Level/Level Properties UI reworked into a magicform.
* New "PromptPre(question, answer, func)" function for prompting the
  user with the developer shell, but pre-filling in an answer for them
  to either post or edit.
* magicform has a PromptUser field option for simple Text/Int fields
  which present as buttons, so magicform can prompt and update the
  variable itself.
* Don't show the _autosave.doodad in the Doodad Dropper window.
This commit is contained in:
Noah 2022-03-06 22:16:09 -08:00
parent d0ae46402b
commit 2fab31d97b
2 changed files with 29 additions and 18 deletions

View File

@ -18,8 +18,8 @@ if (color === 'white') {
} }
function setupAnimations(color) { function setupAnimations(color) {
let left = color === 'blue' ? 'blu-wl' : color+'-wl', let left = color === 'blue' ? 'blu-wl' : color + '-wl',
right = color === 'blue' ? 'blu-wr' : color+'-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'];
@ -71,7 +71,8 @@ function main() {
myPt = Self.Position(); myPt = Self.Position();
// If the player is within aggro range, move towards. // If the player is within aggro range, move towards.
if (Math.abs(playerPt.X - myPt.X) < aggroX && Math.abs(playerPt.Y - myPt.Y) < aggroY) { if ((Math.abs(playerPt.X - myPt.X) < aggroX && Math.abs(playerPt.Y - myPt.Y) < aggroY)
|| (Level.Difficulty > 0)) {
direction = playerPt.X < myPt.X ? "left" : "right"; direction = playerPt.X < myPt.X ? "left" : "right";
followPlayer = true; followPlayer = true;
@ -134,11 +135,16 @@ function playerControls() {
// will be hostile towards the player). Boring players will not be chased after and // will be hostile towards the player). Boring players will not be chased after and
// the Azulian will not harm them if they make contact. // the Azulian will not harm them if they make contact.
function isPlayerFood(actor) { function isPlayerFood(actor) {
// Not a player or is invulnerable. // Not a player or is invulnerable, or Peaceful difficulty.
if (!actor.IsPlayer() || actor.Invulnerable()) { if (!actor.IsPlayer() || actor.Invulnerable() || Level.Difficulty < 0) {
return false; return false;
} }
// On hard mode they are hostile to any player.
if (Level.Difficulty > 0) {
return true;
}
// Azulians are friendly to Thieves and other Azulians. // Azulians are friendly to Thieves and other Azulians.
if (actor.Doodad().Filename === "thief.doodad" || actor.Doodad().Title.indexOf("Azulian") > -1) { if (actor.Doodad().Filename === "thief.doodad" || actor.Doodad().Title.indexOf("Azulian") > -1) {
return false; return false;

View File

@ -1,8 +1,8 @@
// Bird // Bird
let speed = 4, 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";
@ -72,7 +72,7 @@ function main() {
// Scan for the player character and dive. // Scan for the player character and dive.
try { try {
AI_ScanForPlayer() AI_ScanForPlayer()
} catch(e) { } catch (e) {
console.error("Error in AI_ScanForPlayer: %s", e); console.error("Error in AI_ScanForPlayer: %s", e);
} }
} }
@ -84,7 +84,7 @@ function main() {
// If diving, exit - don't edit animation. // If diving, exit - don't edit animation.
if (state === states.diving) { if (state === states.diving) {
Self.ShowLayerNamed("dive-"+direction); Self.ShowLayerNamed("dive-" + direction);
lastDirection = direction; lastDirection = direction;
return; return;
} }
@ -109,6 +109,11 @@ function main() {
// It's not hostile towards characters that can fly (having // It's not hostile towards characters that can fly (having
// no gravity). // no gravity).
function AI_ScanForPlayer() { function AI_ScanForPlayer() {
// If Peaceful difficulty, do not attack.
if (Level.Difficulty < 0) {
return
}
let stepY = 12, // number of pixels to skip let stepY = 12, // number of pixels to skip
stepX = stepY, stepX = stepY,
limit = stepX * 20, // furthest we'll scan limit = stepX * 20, // furthest we'll scan
@ -153,14 +158,14 @@ function player() {
// they aren't seen to be moving downwards, cancel the dive. // they aren't seen to be moving downwards, cancel the dive.
let lastPoint = Self.Position(); let lastPoint = Self.Position();
setInterval(() => { setInterval(() => {
let nowAt = Self.Position(); let nowAt = Self.Position();
if (nowAt.Y > lastPoint.Y) { if (nowAt.Y > lastPoint.Y) {
falling = true; falling = true;
} else { } else {
falling = false; falling = false;
} }
lastPoint = nowAt; lastPoint = nowAt;
}, 100); }, 100);
Events.OnKeypress((ev) => { Events.OnKeypress((ev) => {
Vx = 0; Vx = 0;
@ -198,7 +203,7 @@ function player() {
} else { } else {
// Hover in place. // Hover in place.
if (!Self.IsAnimating()) { if (!Self.IsAnimating()) {
Self.PlayAnimation("fly-"+direction); Self.PlayAnimation("fly-" + direction);
} }
diving = false; diving = false;
} }