Core tests / core (push) Successful in 9m57s
Full verification / application (push) Failing after 5m16s
Full verification / local-brain (push) Failing after 6m15s
Realm simulation / simulated-live-world (push) Failing after 5m32s
WoW integration lab / real-worldserver (push) Canceled after 17m23s
Source branch: feature/ai-brain-router Source commit: c2a09e0460465201a58aaab56c71424e9a96405e
85 lines
3.5 KiB
TypeScript
85 lines
3.5 KiB
TypeScript
import type {Bot,PopulationPlan,State,WorldTrigger} from './types';
|
|
|
|
function scoreCandidate(bot:Bot,state:State,zone:string){
|
|
const home=state.homes.find(h=>h.id===bot.homeId);
|
|
let score=0;
|
|
if(bot.zone===zone)score+=60;
|
|
if(home?.zone===zone)score+=50;
|
|
if(bot.routine.preferredZones.includes(zone))score+=35;
|
|
score+=Math.round(bot.personality.sociability*0.15);
|
|
score+=Math.round(bot.personality.curiosity*0.1);
|
|
if(bot.simulationBand==='background')score+=10;
|
|
if(bot.simulationBand==='dormant')score+=5;
|
|
if(bot.status==='offline')score+=4;
|
|
if(bot.tier==='hero')score+=2;
|
|
return score;
|
|
}
|
|
|
|
export function runPopulationDirector(state:State,trigger:WorldTrigger):PopulationPlan{
|
|
const living=state.bots.filter(b=>b.status!=='dead'&&b.status!=='retired');
|
|
const active=state.bots.filter(b=>b.status==='online');
|
|
const activeInZone=active.filter(b=>b.zone===trigger.zone);
|
|
const foreground=state.bots.filter(b=>b.simulationBand==='foreground'&&b.status!=='dead'&&b.status!=='retired');
|
|
const background=state.bots.filter(b=>b.simulationBand==='background'&&b.status!=='dead'&&b.status!=='retired');
|
|
const settings=state.settings.population;
|
|
const target=Math.min(settings.defaultZoneTarget,settings.zoneMax);
|
|
const requested=Math.max(0,target-activeInZone.length);
|
|
const capacity=Math.max(0,Math.min(
|
|
settings.zoneMax-activeInZone.length,
|
|
settings.serverMax-active.length,
|
|
settings.foregroundMax-foreground.length,
|
|
settings.backgroundMax-background.length+requested
|
|
));
|
|
|
|
const rejectedReasons:string[]=[];
|
|
if(requested===0)rejectedReasons.push('Zone already meets its living population target.');
|
|
if(capacity===0&&requested>0)rejectedReasons.push('Population request blocked by zone, server, or simulation capacity.');
|
|
|
|
const candidates=living
|
|
.filter(b=>b.zone!==trigger.zone||b.status!=='online')
|
|
.filter(b=>b.simulationBand!=='foreground')
|
|
.map(bot=>({bot,score:scoreCandidate(bot,state,trigger.zone)}))
|
|
.filter(x=>x.score>=20)
|
|
.sort((a,b)=>b.score-a.score||a.bot.name.localeCompare(b.bot.name));
|
|
|
|
const count=Math.min(requested,capacity,candidates.length);
|
|
const selectedBotIds=candidates.slice(0,count).map(x=>x.bot.id);
|
|
if(requested>0&&selectedBotIds.length<Math.min(requested,capacity))rejectedReasons.push('Not enough believable existing residents were available; no synthetic identities were injected.');
|
|
|
|
return {
|
|
id:crypto.randomUUID(),
|
|
trigger,
|
|
target,
|
|
activeBefore:activeInZone.length,
|
|
requested,
|
|
capacity,
|
|
selectedBotIds,
|
|
rejectedReasons,
|
|
createdAt:new Date().toISOString()
|
|
};
|
|
}
|
|
|
|
export function applySimulationPopulationPlan(state:State,plan:PopulationPlan){
|
|
for(const id of plan.selectedBotIds){
|
|
const bot=state.bots.find(b=>b.id===id);
|
|
if(!bot||bot.status==='dead'||bot.status==='retired')continue;
|
|
bot.status='online';
|
|
bot.zone=plan.trigger.zone;
|
|
bot.simulationBand='foreground';
|
|
bot.goal=`Spend time in ${plan.trigger.zone} for a believable personal reason while continuing my own life.`;
|
|
}
|
|
for(const bot of state.bots){
|
|
if(bot.status==='dead'||bot.status==='retired'||plan.selectedBotIds.includes(bot.id))continue;
|
|
if(bot.zone===plan.trigger.zone&&bot.status==='online')bot.simulationBand='foreground';
|
|
else if(bot.status==='online')bot.simulationBand='background';
|
|
}
|
|
}
|
|
|
|
export function chooseHomeForNewResident(state:State,bot:Bot){
|
|
const candidates=state.homes
|
|
.filter(h=>h.type!=='homeless'&&h.residentIds.length<h.capacity)
|
|
.map(home=>({home,score:(home.zone===state.director.zone?40:0)+(home.zone===bot.zone?60:0)+home.safety}))
|
|
.sort((a,b)=>b.score-a.score);
|
|
return candidates[0]?.home;
|
|
}
|