mirror of
https://github.com/gooba42/adventureland.git
synced 2026-10-14 10:33:47 -05:00
Merge pull request #192 from Crowns3bc/new-"spawns"-mechanic
New "spawns" mechanic
This commit is contained in:
+71
-6
@@ -540,7 +540,7 @@ function render_monster(monster)
|
|||||||
if(def.immune) html+=info_line({line:"IMMUNE",color:"#AEAEAE"});
|
if(def.immune) html+=info_line({line:"IMMUNE",color:"#AEAEAE"});
|
||||||
if(def.peaceful) html+=info_line({line:"PEACEFUL",color:"#54B25F"});
|
if(def.peaceful) html+=info_line({line:"PEACEFUL",color:"#54B25F"});
|
||||||
if(def.supporter) html+=info_line({line:"SUPPORTER",color:"#CA5931"});
|
if(def.supporter) html+=info_line({line:"SUPPORTER",color:"#CA5931"});
|
||||||
if(def.spawns) html+=info_line({line:"SPAWNS",color:"#AEAEAE"});
|
//if (def.spawns) html += info_line({ line: "SPAWNS", color: "#AEAEAE" }); this is just adding an extra line to the mob UI
|
||||||
if(def.abilities)
|
if(def.abilities)
|
||||||
{
|
{
|
||||||
for(var id in def.abilities)
|
for(var id in def.abilities)
|
||||||
@@ -549,11 +549,76 @@ function render_monster(monster)
|
|||||||
html+=info_line({name:def.abilities[id].aura&&"AURA"||"ABILITY",color:"#FC5F39",value:G.skills[id].name.toUpperCase(),onclick:"dialogs_target=xtarget||ctarget; render_skill('#topleftcornerdialog','"+id+"')"});
|
html+=info_line({name:def.abilities[id].aura&&"AURA"||"ABILITY",color:"#FC5F39",value:G.skills[id].name.toUpperCase(),onclick:"dialogs_target=xtarget||ctarget; render_skill('#topleftcornerdialog','"+id+"')"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(def.spawns)
|
if (def.spawns) {
|
||||||
{
|
// Collect info
|
||||||
def.spawns.forEach(function(s){
|
const spawnInfo = {};
|
||||||
html+=info_line({name:"SPAWNS",color:"#237B2A",value:G.monsters[s[1]].name.toUpperCase(),onclick:"render_monster_info('"+s[1]+"')"});
|
|
||||||
})
|
def.spawns.forEach(function (s) {
|
||||||
|
const condition = s[0];
|
||||||
|
const name = s[1];
|
||||||
|
const count = s[2] || 1;
|
||||||
|
|
||||||
|
if (!spawnInfo[name]) {
|
||||||
|
spawnInfo[name] = { timers: [], thresholds: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof condition === "number") {
|
||||||
|
spawnInfo[name].timers.push({ interval: condition, count });
|
||||||
|
} else if (typeof condition === "string" && condition.startsWith("hp:")) {
|
||||||
|
const threshold = parseFloat(condition.split(":")[1]);
|
||||||
|
spawnInfo[name].thresholds.push({ threshold, count });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build lines
|
||||||
|
Object.keys(spawnInfo).forEach((name) => {
|
||||||
|
const info = spawnInfo[name];
|
||||||
|
let lines = [];
|
||||||
|
|
||||||
|
// Timers
|
||||||
|
info.timers.forEach(t => {
|
||||||
|
lines.push(`${t.count} ${G.monsters[name].name}${t.count > 1 ? "s" : ""} every ${t.interval}ms`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// HP thresholds
|
||||||
|
if (info.thresholds.length === 1) {
|
||||||
|
const t = info.thresholds[0];
|
||||||
|
lines.push(`${t.count} ${G.monsters[name].name}${t.count > 1 ? "s" : ""} at ${t.threshold * 100}% hp`);
|
||||||
|
} else if (info.thresholds.length > 1) {
|
||||||
|
// Sort thresholds high → low
|
||||||
|
info.thresholds.sort((a, b) => b.threshold - a.threshold);
|
||||||
|
|
||||||
|
const percents = info.thresholds.map(t => t.threshold * 100);
|
||||||
|
const counts = [...new Set(info.thresholds.map(t => t.count))];
|
||||||
|
|
||||||
|
if (counts.length === 1) {
|
||||||
|
// Check if evenly spaced
|
||||||
|
const diffs = percents.map((p, i) => i > 0 ? percents[i - 1] - p : null).slice(1);
|
||||||
|
const allEqual = diffs.every(d => d === diffs[0]);
|
||||||
|
|
||||||
|
if (allEqual) {
|
||||||
|
// Summarized
|
||||||
|
lines.push(`${counts[0]} ${G.monsters[name].name}${counts[0] > 1 ? "s" : ""} every ${diffs[0]}% hp`);
|
||||||
|
} else {
|
||||||
|
// Generic
|
||||||
|
lines.push(`Spawns ${G.monsters[name].name} at hp thresholds`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Generic if counts differ
|
||||||
|
lines.push(`Spawns ${G.monsters[name].name} at hp thresholds`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to tooltip
|
||||||
|
lines.forEach(line => {
|
||||||
|
html += info_line({
|
||||||
|
name: "SPAWNS",
|
||||||
|
color: "#237B2A",
|
||||||
|
value: line,
|
||||||
|
onclick: "render_monster_info('" + name + "')"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if(monster.target) html+=info_line({name:"TRG",color:"orange",value:monster.target});
|
if(monster.target) html+=info_line({name:"TRG",color:"orange",value:monster.target});
|
||||||
if(monster.pet)
|
if(monster.pet)
|
||||||
|
|||||||
+61
-29
@@ -12012,35 +12012,67 @@ function update_instance(instance) {
|
|||||||
set_ghash(aggressives, monster, 32);
|
set_ghash(aggressives, monster, 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (monster.target && monster.spawns && get_player(monster.target) && !is_disabled(monster)) {
|
if (monster.target && monster.spawns && get_player(monster.target) && !is_disabled(monster)) {
|
||||||
monster.spawns.forEach(function (spi) {
|
monster.spawns.forEach((spi) => {
|
||||||
var interval = spi[0];
|
const condition = spi[0]; // interval or "hp:0.75"
|
||||||
var name = spi[1];
|
const name = spi[1]; // monster type
|
||||||
if (!monster.last[name] || mssince(monster.last[name]) > interval) {
|
const count = spi[2] || 1; // default to 1
|
||||||
var pname = random_one(Object.keys(monster.points));
|
|
||||||
var player = get_player(pname);
|
// --- Timed spawns (existing) ---
|
||||||
if (!player || player.npc || distance(monster, player) > 400) {
|
if (typeof condition === "number") {
|
||||||
return;
|
if (!monster.last[name] || mssince(monster.last[name]) > condition) {
|
||||||
}
|
for (let i = 0; i < count; i++) {
|
||||||
if (!is_same(player, get_player(monster.target), true)) {
|
const pname = random_one(Object.keys(monster.points));
|
||||||
return;
|
const player = get_player(pname);
|
||||||
}
|
if (!player || player.npc || distance(monster, player) > 400) return;
|
||||||
monster.last[name] = new Date();
|
if (!is_same(player, get_player(monster.target), true)) return;
|
||||||
var spot = safe_xy_nearby(player.map, player.x + Math.random() * 20 - 10, player.y + Math.random() * 20 - 10);
|
|
||||||
if (!spot) {
|
monster.last[name] = new Date();
|
||||||
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,
|
new_monster(instance.name, {
|
||||||
stype: "spawn",
|
type: name,
|
||||||
x: spot.x,
|
stype: "spawn",
|
||||||
y: spot.y,
|
x: spot.x,
|
||||||
target: player.name,
|
y: spot.y,
|
||||||
master: monster.id,
|
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() {
|
function attack_target_or_move() {
|
||||||
var player = players[name_to_id[monster.target]];
|
var player = players[name_to_id[monster.target]];
|
||||||
if (player && ssince(monster.last.attacked) > 20 && Math.random() > monster.rage * 0.99) {
|
if (player && ssince(monster.last.attacked) > 20 && Math.random() > monster.rage * 0.99) {
|
||||||
|
|||||||
Reference in New Issue
Block a user