Tune Princess Lima v2 boss balance and Sun Crystal aid
All checks were successful
Build Org Website / build (push) Successful in 37s

This commit is contained in:
gitea-actions
2026-07-30 15:36:59 +01:00
parent 6066f486de
commit 563d4b63cc
30 changed files with 59 additions and 21 deletions

0
assets/images/play/princess-lima/actor-atlas-v2.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 221 KiB

After

Width:  |  Height:  |  Size: 221 KiB

0
assets/images/play/princess-lima/effects-atlas-v2.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

0
assets/images/play/princess-lima/portrait-atlas-v2.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

0
assets/images/play/princess-lima/world-tiles-v2.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

0
assets/maps/princess-lima/bossArena.json Normal file → Executable file
View File

0
assets/maps/princess-lima/camp.json Normal file → Executable file
View File

0
assets/maps/princess-lima/chamber.json Normal file → Executable file
View File

0
assets/maps/princess-lima/forest.json Normal file → Executable file
View File

0
assets/maps/princess-lima/fortressExterior.json Normal file → Executable file
View File

0
assets/maps/princess-lima/fortressInterior.json Normal file → Executable file
View File

0
assets/maps/princess-lima/mountain.json Normal file → Executable file
View File

0
assets/maps/princess-lima/ruins.json Normal file → Executable file
View File

0
assets/maps/princess-lima/village.json Normal file → Executable file
View File

0
assets/maps/princess-lima/world-tiles.tsj Normal file → Executable file
View File

2
assets/scripts/pages/princess-lima-v2-data.js Normal file → Executable file
View File

@@ -63,7 +63,7 @@
briar_wolf: { role: "boss", boss: true, phases: 2, health: 30, damage: 14, speed: 118, awareness: 430, attackRange: 56, cooldown: 950, telegraph: 380 }, briar_wolf: { role: "boss", boss: true, phases: 2, health: 30, damage: 14, speed: 118, awareness: 430, attackRange: 56, cooldown: 950, telegraph: 380 },
stone_guardian: { role: "boss", boss: true, phases: 3, health: 42, damage: 17, speed: 54, awareness: 430, attackRange: 74, cooldown: 1350, telegraph: 620 }, stone_guardian: { role: "boss", boss: true, phases: 3, health: 42, damage: 17, speed: 54, awareness: 430, attackRange: 74, cooldown: 1350, telegraph: 620 },
captain: { role: "boss", boss: true, phases: 2, health: 36, damage: 15, speed: 78, awareness: 430, attackRange: 54, cooldown: 1050, telegraph: 360 }, captain: { role: "boss", boss: true, phases: 2, health: 36, damage: 15, speed: 78, awareness: 430, attackRange: 54, cooldown: 1050, telegraph: 360 },
malrec: { role: "boss", boss: true, phases: 3, health: 64, damage: 18, speed: 70, awareness: 520, attackRange: 190, cooldown: 1200, telegraph: 520 } malrec: { role: "boss", boss: true, phases: 3, health: 52, damage: 13, speed: 60, awareness: 520, attackRange: 190, cooldown: 1600, telegraph: 760 }
}); });
const ITEMS = Object.freeze({ const ITEMS = Object.freeze({

0
assets/scripts/pages/princess-lima-v2-game.js Normal file → Executable file
View File

0
assets/scripts/pages/princess-lima-v2-maps.js Normal file → Executable file
View File

26
assets/scripts/pages/princess-lima-v2-scenes.js Normal file → Executable file
View File

@@ -143,6 +143,7 @@
this.pathTick = 0; this.pathTick = 0;
this.puzzleProgress = {}; this.puzzleProgress = {};
this.spawnedObjects = new Set(); this.spawnedObjects = new Set();
this.sunAidUsed = false;
} }
create() { create() {
controller.scene = this; controller.scene = this;
@@ -366,10 +367,23 @@
return; return;
} }
if (action === "boss-mechanic") { if (action === "boss-mechanic") {
if (this.sunAidUsed) return controller.status("The Sun Crystal is gathering its light again.");
const malrec = this.enemies.getChildren().find((enemy) => enemy.active && enemy.getData("actorId") === "malrec");
if (!malrec) return controller.status("The Sun Crystal is warm, but its moment has not come.");
this.sunAidUsed = true;
controller.state.flags.sun_veil_broken = true; controller.state.flags.sun_veil_broken = true;
controller.state.health = Math.min(controller.state.maxHealth, controller.state.health + 25);
malrec.setData("health", Math.max(1, malrec.getData("health") - 12));
malrec.setData("stunnedUntil", this.time.now + 2100);
malrec.setData("state", "hurt");
malrec.setVelocity(0).setTint(0xffe39a).setTintMode(Phaser.TintModes.FILL);
this.projectiles.forEach((projectile) => projectile.active && projectile.destroy());
this.projectiles = [];
this.time.delayedCall(350, () => malrec.active && malrec.clearTint());
controller.save(); controller.save();
controller.updateHud();
this.cameras.main.flash(200, 255, 230, 150); this.cameras.main.flash(200, 255, 230, 150);
controller.status("The Sun Crystal tears open Malrec's veil."); controller.status("Lima channels the Sun Crystal: Malrec's veil breaks, and your strength returns.");
return; return;
} }
if (action === "block-tutorial") return controller.status("Hold Shift to block. Release and strike during an enemy's recovery."); if (action === "block-tutorial") return controller.status("Hold Shift to block. Release and strike during an enemy's recovery.");
@@ -553,11 +567,15 @@
const id = enemy.getData("actorId"); const id = enemy.getData("actorId");
const phase = enemy.getData("phase"); const phase = enemy.getData("phase");
if (["ranged", "caster", "support"].includes(spec.role) || id === "malrec") { if (["ranged", "caster", "support"].includes(spec.role) || id === "malrec") {
const count = id === "malrec" ? phase * 2 + 1 : 1; const count = id === "malrec" ? phase + 1 : 1;
const preparedReduction = id === "malrec"
? (controller.state.flags.defences_disabled ? 2 : 0) + (controller.state.flags.prisoners_freed ? 2 : 0)
: 0;
const damage = Math.max(8, spec.damage - preparedReduction);
for (let index = 0; index < count; index += 1) { for (let index = 0; index < count; index += 1) {
const base = Phaser.Math.Angle.Between(enemy.x, enemy.y, this.player.x, this.player.y); const base = Phaser.Math.Angle.Between(enemy.x, enemy.y, this.player.x, this.player.y);
const angle = base + (index - (count - 1) / 2) * 0.22; const angle = base + (index - (count - 1) / 2) * (id === "malrec" ? 0.3 : 0.22);
this.spawnProjectile(enemy.x, enemy.y, angle, spec.damage, id === "malrec" ? 185 : 145); this.spawnProjectile(enemy.x, enemy.y, angle, damage, id === "malrec" ? 150 : 145);
} }
return; return;
} }

0
assets/scripts/pages/princess-lima-v2-state.js Normal file → Executable file
View File

0
assets/scripts/pages/princess-lima-v2-systems.js Normal file → Executable file
View File

0
assets/scripts/pages/princess-lima-v2-ui.js Normal file → Executable file
View File

0
assets/scripts/vendor/easystar-0.4.4.min.js vendored Normal file → Executable file
View File

View File

@@ -816,3 +816,9 @@ at <ScriptBlock>, /home/zaine/master-folder/org-platform/org_web/build-logs/gite
2026-07-30T13:59:09.5410036+01:00 [INFO] Running authoring server tests with /home/zaine/master-folder/org-platform/authoring-service/.venv/bin/python. 2026-07-30T13:59:09.5410036+01:00 [INFO] Running authoring server tests with /home/zaine/master-folder/org-platform/authoring-service/.venv/bin/python.
2026-07-30T13:59:09.6127470+01:00 [INFO] Authoring server tests passed: ran=0, failures=0, errors=0, skipped=0, exit=0 2026-07-30T13:59:09.6127470+01:00 [INFO] Authoring server tests passed: ran=0, failures=0, errors=0, skipped=0, exit=0
2026-07-30T13:59:09.8840005+01:00 [INFO] Sent authoring server test notification. 2026-07-30T13:59:09.8840005+01:00 [INFO] Sent authoring server test notification.
2026-07-30T15:01:49.5468944+01:00 [INFO] Prepared current build status for zaine/org_web: severity=Info, status=success
2026-07-30T15:01:49.5644329+01:00 [INFO] Fetching recent Gitea Actions runs for zaine/org_web.
2026-07-30T15:01:51.1104245+01:00 [INFO] Sent build status notification with 1 embed(s).
2026-07-30T15:01:51.1476262+01:00 [INFO] Running authoring server tests with /home/zaine/master-folder/org-platform/authoring-service/.venv/bin/python.
2026-07-30T15:01:51.2921733+01:00 [INFO] Authoring server tests passed: ran=0, failures=0, errors=0, skipped=0, exit=0
2026-07-30T15:01:51.6686257+01:00 [INFO] Sent authoring server test notification.

0
docs/princess-lima-v2-implementation.md Normal file → Executable file
View File

View File

@@ -4,7 +4,7 @@
See the categories: @@html:<a href="../home/categories.html">Categories</a>@@ See the categories: @@html:<a href="../home/categories.html">Categories</a>@@
* Posts: * Posts:
- [[file:career/career-list.org][Career List]] @@html:<span class="post-date">30-07-2026 14:54</span>@@ - [[file:career/career-list.org][Career List]] @@html:<span class="post-date">30-07-2026 15:01</span>@@
- [[file:career/cross-site-scripting-xss.org][Cross-Site Scripting (XSS)]] @@html:<span class="post-date">01-06-2026 10:21</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@ - [[file:career/cross-site-scripting-xss.org][Cross-Site Scripting (XSS)]] @@html:<span class="post-date">01-06-2026 10:21</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@
- [[file:career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:<span class="post-date">11-03-2026 17:18</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@ - [[file:career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:<span class="post-date">11-03-2026 17:18</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@
- [[file:career/javascript.org][Understands the Javascript language]] @@html:<span class="post-date">11-03-2026 16:52</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@ - [[file:career/javascript.org][Understands the Javascript language]] @@html:<span class="post-date">11-03-2026 16:52</span>@@ @@html:<a href="/tags/learning.html"><span class="post-tag">learning</span></a>@@ @@html:<a href="/tags/notes.html"><span class="post-tag">notes</span></a>@@

View File

@@ -104,17 +104,17 @@ flowchart TD
n43 --> n49 n43 --> n49
n50["Tag: website"] n50["Tag: website"]
n43 --> n50 n43 --> n50
n51["Tag: update"] n51["Tag: life"]
n43 --> n51 n43 --> n51
n52["Tag: life"] n52["Tag: update"]
n43 --> n52 n43 --> n52
n53["Tag: education"] n53["Tag: insights"]
n43 --> n53 n43 --> n53
n54["Tag: insights"] n54["Tag: education"]
n43 --> n54 n43 --> n54
n55["Tag: emacs"] n55["Tag: reading"]
n43 --> n55 n43 --> n55
n56["Tag: reading"] n56["Tag: emacs"]
n43 --> n56 n43 --> n56
n57["Tag: maths"] n57["Tag: maths"]
n43 --> n57 n43 --> n57
@@ -224,12 +224,12 @@ flowchart TD
click n48 "tags/notes.html" "Tag: notes" click n48 "tags/notes.html" "Tag: notes"
click n49 "tags/review.html" "Tag: review" click n49 "tags/review.html" "Tag: review"
click n50 "tags/website.html" "Tag: website" click n50 "tags/website.html" "Tag: website"
click n51 "tags/update.html" "Tag: update" click n51 "tags/life.html" "Tag: life"
click n52 "tags/life.html" "Tag: life" click n52 "tags/update.html" "Tag: update"
click n53 "tags/education.html" "Tag: education" click n53 "tags/insights.html" "Tag: insights"
click n54 "tags/insights.html" "Tag: insights" click n54 "tags/education.html" "Tag: education"
click n55 "tags/emacs.html" "Tag: emacs" click n55 "tags/reading.html" "Tag: reading"
click n56 "tags/reading.html" "Tag: reading" click n56 "tags/emacs.html" "Tag: emacs"
click n57 "tags/maths.html" "Tag: maths" click n57 "tags/maths.html" "Tag: maths"
click n59 "posts/posts-intro.html" "Posts Introduction" click n59 "posts/posts-intro.html" "Posts Introduction"
click n60 "posts/posts-list.html" "Posts List" click n60 "posts/posts-list.html" "Posts List"
@@ -318,12 +318,12 @@ flowchart TD
- [[file:tags/notes.org][Tag: notes]] - [[file:tags/notes.org][Tag: notes]]
- [[file:tags/review.org][Tag: review]] - [[file:tags/review.org][Tag: review]]
- [[file:tags/website.org][Tag: website]] - [[file:tags/website.org][Tag: website]]
- [[file:tags/update.org][Tag: update]]
- [[file:tags/life.org][Tag: life]] - [[file:tags/life.org][Tag: life]]
- [[file:tags/education.org][Tag: education]] - [[file:tags/update.org][Tag: update]]
- [[file:tags/insights.org][Tag: insights]] - [[file:tags/insights.org][Tag: insights]]
- [[file:tags/emacs.org][Tag: emacs]] - [[file:tags/education.org][Tag: education]]
- [[file:tags/reading.org][Tag: reading]] - [[file:tags/reading.org][Tag: reading]]
- [[file:tags/emacs.org][Tag: emacs]]
- [[file:tags/maths.org][Tag: maths]] - [[file:tags/maths.org][Tag: maths]]
- posts - posts
- [[file:posts/posts-intro.org][Posts Introduction]] - [[file:posts/posts-intro.org][Posts Introduction]]

View File

@@ -92,3 +92,17 @@ test("combat phases, hitboxes and enemy states are deterministic", () => {
stunned: false, telegraphDone: true, attackDone: true, cooldownDone: true stunned: false, telegraphDone: true, attackDone: true, cooldownDone: true
}), "telegraph"); }), "telegraph");
}); });
test("Malrec is demanding but leaves readable counterplay", () => {
const malrec = data.ENEMIES.malrec;
assert.equal(malrec.phases, 3);
assert.ok(malrec.health <= 52);
assert.ok(malrec.damage <= 13);
assert.ok(malrec.telegraph >= 750);
assert.ok(malrec.cooldown >= 1500);
const scenes = source("assets/scripts/pages/princess-lima-v2-scenes.js");
assert.match(scenes, /phase \+ 1/);
assert.match(scenes, /state\.health \+ 25/);
assert.match(scenes, /defences_disabled/);
assert.match(scenes, /prisoners_freed/);
});

0
tests/princess-lima-v2-state.test.cjs Normal file → Executable file
View File

0
tools/generate-princess-lima-maps.mjs Normal file → Executable file
View File

0
tools/generate-princess-lima-v2-assets.py Normal file → Executable file
View File