Files
Viano-Core/tests/clientless/test_adventure_group_plan.py
T
Nico d6fea6ee68
clang PCH / build (push) Canceled after 0s
GCC PCH / build (push) Canceled after 0s
Add AdventureBot groups, raid preparation and shared travel
Implement native bot recruitment and player admission, leader-owned destinations, intent-specific capacities, preparation scheduling and shared graph and flight travel. Support native group instance visits and separate raid entrances.

Include pending personality-driven faction PvP and solo fleeing, preserving the absolute group fleeing exclusion. Add regression fixtures, migration, documentation and test-server evidence.
2026-10-28 15:00:41 +01:00

63 lines
4.4 KiB
Python

"""Execute production leader-plan inheritance without modifying members' own days."""
from pathlib import Path
import subprocess,tempfile
root=Path(__file__).resolve().parents[2]
s=(root/'src/server/game/World/AdventureBehaviorMgr.cpp').read_text()
sig='std::string AdventureBehaviorMgr::InteractionSchedule('
start=s.index(sig);begin=s.index('{',start);end=begin+1;depth=1
while depth:depth+=(s[end]=='{')-(s[end]=='}');end+=1
schedule=s[start:end]
a=s.index('AdventureGroupPlan AdventureBehaviorMgr::GroupPlan(')
code=r'''
#include "AdventureBehaviorPolicy.h"
#include "AdventureInstancePolicy.h"
#include <cassert>
#include <ctime>
#include <unordered_map>
using uint32=unsigned;
struct Guid{unsigned id;unsigned GetCounter(){return id;}};
struct Player{Guid guid;Guid GetGUID(){return guid;}};
struct AdventureGroupPlan{bool Enabled=false,Forming=false;std::string Intent,Location,NextIntent,NextLocation;time_t Deadline=0;};
namespace GameTime{time_t GetGameTime(){return 100;}}
std::tm Local(time_t){std::tm tm{};tm.tm_hour=5;return tm;}unsigned DateOf(std::tm){return 1;}
struct AdventureBehaviorMgr{
struct Record{bool Enabled=true,Schedule=true,GroupOverride=false,Dirty=false;int Hour=-1;unsigned Date=1;std::string Intent,Location,WantedIntent,WantedLocation,ManualNextIntent,ManualNextLocation;std::string PersonalIntent,PersonalLocation;time_t PersonalDeadline=0;time_t Deadline=3600;AdventureBehaviorPolicy::Day Plan;AdventureInstancePolicy::Visit Instance;};
std::unordered_map<unsigned,Record>_records;int changes=0;
void Generate(Player*,Record&r,unsigned date){r.Date=date;}
void SetWanted(Player*,Record&r,std::string const&i,std::string const&l,time_t end){++changes;r.WantedIntent=i;r.WantedLocation=l;r.Deadline=end;}
std::string InteractionSchedule(Player*);void ResumePersonalPlan(Player*);AdventureGroupPlan GroupPlan(Player*);bool AdoptGroup(Player*,Player*);
};
'''+schedule+'\n'+s[a:]+r'''
int main(){
AdventureBehaviorMgr mgr;Player leader{{29}},member{{31}};auto& a=mgr._records[29];auto& b=mgr._records[31];
a.Intent="groupformation";a.Location="leader-capital";a.Plan[5]={"groupformation","leader-capital"};a.Plan[6]={"instance","deadmines"};
b.Intent="groupformation";b.Location="other-capital";b.Plan[5]={"groupformation","other-capital"};b.Plan[6]={"instance","shadowfang"};
auto plan=mgr.GroupPlan(&member);assert(plan.Forming&&plan.NextIntent=="instance"&&plan.NextLocation=="shadowfang");
assert(mgr.AdoptGroup(&member,&leader));assert(b.WantedLocation=="leader-capital"&&b.Deadline==a.Deadline&&b.Schedule);
assert(b.Plan[6].Location=="shadowfang"); // own future plan remains available after departure
a.Intent="instance";a.Location="deadmines";a.Deadline=7200;
assert(mgr.AdoptGroup(&member,&leader));assert(b.WantedIntent=="instance"&&b.WantedLocation=="deadmines"&&b.Deadline==7200);
b.Instance.Active=true;b.Instance.Stage=AdventureInstancePolicy::Phase::Inside;a.Location="other";
int changes=mgr.changes;assert(mgr.AdoptGroup(&member,&leader)&&mgr.changes==changes);
b.Instance.Stage=AdventureInstancePolicy::Phase::Travel;mgr.AdoptGroup(&member,&leader);assert(b.WantedLocation=="other");
a.Enabled=false;assert(!mgr.AdoptGroup(&member,&leader));
b.Instance.Active=false;mgr.ResumePersonalPlan(&member);
assert(!b.GroupOverride&&b.WantedIntent=="groupformation"&&b.WantedLocation=="other-capital");
b.Schedule=false;b.Intent="groupformation";b.ManualNextIntent="raid";b.ManualNextLocation="molten-core";
plan=mgr.GroupPlan(&member);assert(plan.Forming&&plan.NextIntent=="raid"&&plan.NextLocation=="molten-core");
// Different goals are inherited without inventing a personal intent change.
b.GroupOverride=false;b.Instance.Active=false;b.Intent=b.WantedIntent="social";
b.Location=b.WantedLocation="personal-place";b.Deadline=2000;
a.Enabled=true;a.Intent="social";a.Location="leader-place";
assert(mgr.AdoptGroup(&member,&leader));b.Location="leader-place";
assert(mgr.InteractionSchedule(&member)=="social:personal-place");
mgr.ResumePersonalPlan(&member);
assert(b.WantedLocation=="personal-place"&&mgr.InteractionSchedule(&member)=="social:personal-place");
}
'''
with tempfile.TemporaryDirectory() as d:
p=Path(d);(p/'plan.cpp').write_text(code)
subprocess.run(['g++','-std=c++17','-I'+str(root/'src/server/game/World'),str(p/'plan.cpp'),'-o',str(p/'plan')],check=True)
subprocess.run([str(p/'plan')],check=True)
print('Production group plans: leader meeting/goal/deadline inheritance, untouched personal day, manual preparation and instance-state guards passed.')