From 066b4aeb6cf1ebbb0557df6956f8f8815db4a925 Mon Sep 17 00:00:00 2001 From: Crowns3bc <44653214+Crowns3bc@users.noreply.github.com> Date: Thu, 21 Aug 2025 14:26:39 -0600 Subject: [PATCH] New "spawns" mechanic the current .spawns property for a mob only allows for spawning 1 mob at a set interval. this doesnt change that, but now also allows for a mob to spawn additional mobs at %hp thresholds. it also allows for a quantity of mobs to be spawned for both versions. Example: for franky he has "spawns":[[200,"nerfedmummy"]] it can now be "spawns":[[200,"nerfedmummy",2]] and he would spawn 2 mummies at a time per interval or "spawns":[["hp:0.50", "nerfedmummy", 3]] and he will spawn 3 mummies once he reaches 50% hp --- node/server.js | 90 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 29 deletions(-) diff --git a/node/server.js b/node/server.js index cbfb7a1..46b541c 100644 --- a/node/server.js +++ b/node/server.js @@ -11967,35 +11967,67 @@ function update_instance(instance) { set_ghash(aggressives, monster, 32); } } - if (monster.target && monster.spawns && get_player(monster.target) && !is_disabled(monster)) { - monster.spawns.forEach(function (spi) { - var interval = spi[0]; - var name = spi[1]; - if (!monster.last[name] || mssince(monster.last[name]) > interval) { - var pname = random_one(Object.keys(monster.points)); - var player = get_player(pname); - if (!player || player.npc || distance(monster, player) > 400) { - return; - } - if (!is_same(player, get_player(monster.target), true)) { - return; - } - monster.last[name] = new Date(); - var spot = safe_xy_nearby(player.map, player.x + Math.random() * 20 - 10, player.y + Math.random() * 20 - 10); - if (!spot) { - return; - } - new_monster(instance.name, { - type: name, - stype: "spawn", - x: spot.x, - y: spot.y, - target: player.name, - master: monster.id, - }); - } - }); - } + if (monster.target && monster.spawns && get_player(monster.target) && !is_disabled(monster)) { + monster.spawns.forEach((spi) => { + const condition = spi[0]; // interval or "hp:0.75" + const name = spi[1]; // monster type + const count = spi[2] || 1; // default to 1 + + // --- Timed spawns (existing) --- + if (typeof condition === "number") { + if (!monster.last[name] || mssince(monster.last[name]) > condition) { + for (let i = 0; i < count; i++) { + const pname = random_one(Object.keys(monster.points)); + const player = get_player(pname); + if (!player || player.npc || distance(monster, player) > 400) return; + if (!is_same(player, get_player(monster.target), true)) return; + + monster.last[name] = new Date(); + const spot = safe_xy_nearby(player.map, player.x + Math.random() * 20 - 10, player.y + Math.random() * 20 - 10); + if (!spot) return; + + new_monster(instance.name, { + type: name, + stype: "spawn", + x: spot.x, + y: spot.y, + target: player.name, + master: monster.id, + }); + } + } + } + + // --- HP threshold spawns (new) --- + if (typeof condition === "string" && condition.startsWith("hp:")) { + const threshold = parseFloat(condition.split(":")[1]); // e.g. 0.75 + const currentHpRatio = monster.hp / monster.max_hp; + const key = name + "_hp_" + threshold; + + if (currentHpRatio <= threshold && !monster.last[key]) { // trigger once per fight + for (let i = 0; i < count; i++) { + const pname = random_one(Object.keys(monster.points)); + const player = get_player(pname); + if (!player || player.npc || distance(monster, player) > 400) return; + if (!is_same(player, get_player(monster.target), true)) return; + + const spot = safe_xy_nearby(player.map, player.x + Math.random() * 20 - 10, player.y + Math.random() * 20 - 10); + if (!spot) return; + + new_monster(instance.name, { + type: name, + stype: "spawn", + x: spot.x, + y: spot.y, + target: player.name, + master: monster.id, + }); + } + monster.last[key] = true; // mark this threshold as triggered + } + } + }); + } function attack_target_or_move() { var player = players[name_to_id[monster.target]]; if (player && ssince(monster.last.attacked) > 20 && Math.random() > monster.rage * 0.99) {