Add danger-aware companion selection and native survival assistance
Core tests / core (push) Successful in 39s

This commit is contained in:
Codex
2026-09-22 21:41:51 -04:00
parent 290926f33f
commit a533c7b28a
10 changed files with 167 additions and 17 deletions
+11
View File
@@ -37,3 +37,14 @@ test('offline party members are protected when their identity cannot be checked
assert.match(compileCommunityAction('party',bot('A'),bot('B')),/Party has offline members/);
assert.match(compileCommunityAction('leave',bot('A')),/Party has offline members/);
});
test('recent danger encourages shy companions without overriding hostility or human control',()=>{
const {partyDecision}=require('../.test-build/community.js');const a=bot('A'),b=bot('B');a.personality.sociability=0;b.personality.sociability=0;
assert.equal(partyDecision(a,b).accepted,false);a.world.dangerAt=now();assert.equal(partyDecision(a,b).accepted,true);
b.relationships=[{targetId:'A',affinity:-1}];assert.equal(partyDecision(a,b).accepted,false);b.relationships=[];
b.world.humanControlled=true;assert.equal(partyDecision(a,b).accepted,false);b.world.humanControlled=false;
a.world.dangerAt=now()-601;assert.equal(partyDecision(a,b).accepted,false);
});
test('companion ranking prefers complementary native roles and shared active quests',()=>{
const {companionScore}=require('../.test-build/community.js');const a=bot('A'),b=bot('B'),c=bot('C');a.world.combatRole='tank';b.world.combatRole='healer';c.world.combatRole='damage';assert.ok(companionScore(a,b)>companionScore(a,c));
b.world.combatRole='damage';a.world.quests=[1,2];c.world.quests=[1,2];assert.ok(companionScore(a,c)>companionScore(a,b));
});
+37
View File
@@ -0,0 +1,37 @@
from pathlib import Path
from lupa import LuaRuntime
setup='''
now=1000;os.time=function()return now end;calls={};people={}
function AuthDBQuery(sql)local i=1;return {GetUInt32=function(_,n)return n==0 and i or 10+i end,GetString=function()return i==1 and 'A' or 'B'end,NextRow=function()i=i+1;return i<=2 end} end
function GetPlayersInWorld()return people end
function CreateLuaEvent(fn)tick=fn end
function PrintInfo()end
function PrintError(s)error(s)end
function make(id,name)
local p={id=id,name=name,hp=100,distance=25,ai={}}
function p:GetGUIDLow()return self.id end;function p:GetName()return self.name end;function p:GetAccountId()return 10+self.id end
function p:IsPlayerbot()return not self.human end;function p:IsDead()return self.dead end;function p:GetBotAI()return self.ai end
function p:GetHealthPct()return self.hp end;function p:IsInCombat()return self.combat end
function p:IsTaxi()return self.taxi end;function p:IsCasting()return self.cast end;function p:IsRooted()return false end
function p:GetGroup()return self.group end;function p:GetVictim()return self.enemy end;function p:GetLevel()return 5 end
function p:GetDistance()return self.distance end;function p:GetMapId()return 0 end;function p:GetPhaseMask()return 1 end
function p.ai:GetMaster()return p.master end;function p.ai:SetMaster(m)p.master=m end
function p.ai:HasGameClientMaster()return p.controlled end;function p.ai:IsMovementImpaired()return false end
function p.ai:GetGroupLeader()return leader end;function p.ai:ChangeStrategy(s,state)end
function p.ai:DoSpecificAction(s)table.insert(calls,s);return true end
return p
end
A=make(1,'A');B=make(2,'B');people={A,B};leader=A
function group() local g={GetMembers=function()return {A,B}end,GetMembersCount=function()return 2 end,IsRaidGroup=function()return false end};A.group=g;B.group=g end
function step(n)now=now+n;tick()end
'''
def new():
l=LuaRuntime();l.execute(setup);l.execute((Path(__file__).resolve().parents[1]/'ale/azerothai_survival.lua').read_text());l.execute('AzerothAISetSurvivalEnabled(true)');return l
l=new();l.execute("A.combat=true;A.hp=20;step(0);assert(calls[1]=='flee');step(10);assert(#calls==1);step(10);assert(#calls==2)")
l=new();l.execute("group();A.human=true;B.combat=true;B.hp=20;step(0);assert(#calls==0)")
l=new();l.execute("group();step(0);assert(calls[1]=='follow' and B.master==A)")
l=new();l.execute("group();B.distance=100;step(0);assert(#calls==0)")
l=new();l.execute("A.combat=true;A.hp=20;A.controlled=true;step(0);assert(#calls==0)")
l=new();l.execute("A.combat=true;A.hp=20;step(0);A.combat=false;step(20);assert(calls[2]=='eat' and calls[3]=='drink')")
l=new();l.execute("group();AzerothAISetSurvivalEnabled(false);step(0);assert(#calls==0)")
print('Native survival: retreat cooldown, recovery, regroup range, human-party protection, and disabled grouping passed')