19#include <Tempest/Painter>
20#include <Tempest/Application>
23using namespace Tempest;
25int32_t WorldObjects::MobStates::stateByTime(
gtime t)
const {
27 for(
size_t i=routines.size(); i>0; ) {
29 if(routines[i].time<=t) {
30 return routines[i].state;
34 return routines.back().state;
38void WorldObjects::MobStates::save(
Serialize& fout) {
39 fout.
write(curState,scheme);
40 fout.
write(uint32_t(routines.size()));
41 for(
auto& i:routines) {
42 fout.
write(i.time,i.state);
46void WorldObjects::MobStates::load(
Serialize& fin) {
47 fin.
read(curState,scheme);
51 for(
auto& i:routines) {
52 fin.
read(i.time,i.state);
57 :rangeMin(rangeMin),rangeMax(rangeMax),azi(azi),collectAlgo(collectAlgo),collectType(collectType),flags(flags) {
79 for(
size_t i=0; i<sz; ++i)
80 npcArr[i] = std::make_unique<Npc>(owner,
size_t(-1),
"");
81 for(
size_t i=0; i<npcArr.size(); ++i) {
82 npcArr[i]->load(fin,i,
"/npc/");
87 npcInvalid.resize(sz);
88 for(
size_t i=0; i<npcInvalid.size(); ++i)
89 npcInvalid[i] = std::make_unique<Npc>(owner,
size_t(-1),
"");
90 for(
size_t i=0; i<npcInvalid.size(); ++i)
91 npcInvalid[i]->
load(fin,i,
"/npc_invalid/");
96 for(
size_t i=0; i<sz; ++i) {
98 itemArr.emplace_back(std::move(it));
99 items.
add(itemArr.back().get());
102 for(
auto& i:rootVobs)
107 triggerEvents.resize(sz);
108 for(
auto& i:triggerEvents)
114 for(
auto& i:routines)
117 for(
auto& i:interactiveObj)
127 for(
size_t i=0; i<npcArr.size(); ++i)
128 npcArr[i]->
save(fout,i,
"/npc/");
129 for(
size_t i=0; i<npcInvalid.size(); ++i)
130 npcInvalid[i]->
save(fout,i,
"/npc_invalid/");
133 fout.
write(uint32_t(itemArr.size()));
138 for(
auto& i:rootVobs)
139 i->saveVobTree(fout);
142 fout.
write(uint32_t(triggerEvents.size()));
143 for(
auto& i:triggerEvents)
147 fout.
write(uint32_t(routines.size()));
148 for(
auto& i:routines)
153 auto passive=std::move(sndPerc);
156 bool needSort =
false;
157 for(
size_t i=1; i<npcArr.size(); ++i) {
158 auto& a = npcArr[i-1];
159 auto& b = npcArr[i-0];
160 if(a->handle().id>b->handle().id) {
167 std::sort(npcArr.begin(),npcArr.end(),[](std::unique_ptr<Npc>& a, std::unique_ptr<Npc>& b){
168 return a->handle().id<b->handle().id;
173 const bool freeCam = (camera!=
nullptr && camera->isFree());
174 const auto pl = owner.
player();
175 for(
size_t i=0; i<npcArr.size(); ++i) {
176 auto&
npc = *npcArr[i];
177 uint64_t d = (pl==&
npc ? dtPlayer : dt);
178 if(freeCam && pl==&
npc)
183 for(
auto& i:routines) {
184 auto s = i.stateByTime(owner.
time());
186 setMobState(i.scheme,s);
194 for(
auto& i:interactiveObj)
197 for(
auto i:triggersTk)
202 bullets.remove_if([](
Bullet& b){
206 for(
size_t i=0; i<effects.size();) {
207 if(effects[i].timeUntil<owner.
tickCount()) {
208 effects[i].eff.setActive(
false);
209 effects[i] = std::move(effects.back());
212 effects[i].eff.tick(dt);
219 const float nearDist = 3000*3000;
220 const float farDist = 6000*6000;
222 auto cpos = camera!=
nullptr ? camera->destPosition() : Vec3();
223 auto plPos = pl!=
nullptr ? pl->position() : cpos;
224 for(
auto& i:npcArr) {
225 float dist = (i->position()-plPos).quadLength();
227 npcNear.push_back(i.get());
245 for(
auto& ptr:npcNear) {
257 passivePerceptionProcess(r, *ptr, *pl);
265 for(
size_t i=0;i<npcArr.size();++i)
266 if(npcArr[i].get()==ptr)
272 for(
size_t i=0;i<itemArr.size();++i)
273 if(&itemArr[i]->handle()==ptr)
280 for(
auto& i:interactiveObj) {
289 Npc*
npc =
new Npc(owner,npcInstance,at);
291 if(pos->isLocked()) {
301 npcArr.emplace_back(
npc);
303 Log::e(
"addNpc: ", npcInstance,
" has invalid spawnpoint");
308 npcInvalid.emplace_back(
npc);
320 auto pstr = point==
nullptr ?
"" : point->
name;
321 Npc*
npc =
new Npc(owner,npcInstance,pstr);
326 npcArr.emplace_back(
npc);
333 Log::e(
"insertPlayer: invalid waypoint, using fallback");
338 if(pos->isLocked()) {
347 npcArr.emplace_back(std::move(
npc));
348 return npcArr.back().get();
352 for(
size_t i=0; i<npcArr.size(); ++i){
353 auto&
npc=*npcArr[i];
355 auto ret=std::move(npcArr[i]);
356 npcArr.erase(npcArr.begin() + int32_t(i));
371 npcRemoved.emplace_back(std::move(ptr));
374void WorldObjects::tickNear(uint64_t ) {
375 for(
Npc* i:npcNear) {
376 auto pos = i->position() + Vec3(0,i->translateY(),0);
384 triggerEvents.push_back(e);
387void WorldObjects::tickTriggers(uint64_t ) {
390 auto evt = std::move(triggerEvents);
391 triggerEvents.clear();
398 auto def = std::move(triggersDef);
401 i->processDelayedEvents();
402 if(i->hasDelayedEvents())
403 triggersDef.push_back(i);
410 for(
auto& i:triggers) {
422 static bool doAnim=
true;
428 i->updateAnimation(dt);
431 i.updateAnimation(dt);
436 std::atomic_flag flg = ATOMIC_FLAG_INIT;
438 if(isTargetedBy(*i,dst))
441 return flg.test_and_set();
444bool WorldObjects::isTargetedBy(
Npc& npc,
Npc& dst) {
463 for(
auto& i:npcArr) {
464 if(i->handle().symbol_index()==
instance) {
474 for(
auto& i:itemArr) {
475 if(i->handle().symbol_index()==
instance) {
490 const float r,
const std::function<
void(
Npc&)>& f) {
492 for(
auto& i:npcArr) {
493 auto qDist = (i->position()-Vec3(x,y,z)).quadLength();
500 const float r,
const std::function<
void(
Item&)>& f) {
502 for(
auto& i:itemArr) {
503 auto qDist = (i->position()-Vec3(x,y,z)).quadLength();
510 triggers.emplace_back(tg);
514 for(
auto& i:triggersDef)
517 triggersDef.push_back(&t);
523 for(
auto& i:triggers) {
525 ts->processEvent(evt);
533 for(
auto& i:triggersTk)
536 triggersTk.push_back(&t);
540 for(
auto& i:triggersTk)
542 i = triggersTk.back();
543 triggersTk.pop_back();
549 currentCsCamera = cs;
553 return currentCsCamera;
557 collisionZn.push_back(&z);
561 for(
auto& i:collisionZn)
563 i = collisionZn.back();
564 collisionZn.pop_back();
570 ex.setBullet(
nullptr,owner);
573 e.eff = std::move(ex);
574 e.timeUntil = owner.
tickCount()+e.eff.effectPrefferedTime();
575 effects.push_back(std::move(e));
588 auto m = Tempest::Matrix4x4(vob.rotation.columns[0].x, vob.rotation.columns[1].x, vob.rotation.columns[2].x, vob.position.x,
589 vob.rotation.columns[0].y, vob.rotation.columns[1].y, vob.rotation.columns[2].y, vob.position.y,
590 vob.rotation.columns[0].z, vob.rotation.columns[1].z, vob.rotation.columns[2].z, vob.position.z,
599 auto ret=std::move(i);
600 i = std::move(itemArr.back());
602 items.
del(ret.get());
603 ret->setPhysicsDisable();
617 for(
auto& i:interactiveObj)
619 return i->inventory().itemCount(itemCls);
626 i->onWldItemRemoved(
itm);
631 bullets.emplace_back(owner,
itmId,pos);
632 auto& b = bullets.back();
634 const float rgnBias = 0.f;
635 const float l = dir.length();
636 b.setDirection(dir*speed/l);
637 b.setTargetRange(tgRange + rgnBias);
642 Item* item =
nullptr;
647 if(waypoint !=
nullptr) {
652 item =
addItem(itemInstance, pos, dir);
657 return addItem(itemInstance, pos, {0,0,0});
661 if(itemInstance==
size_t(-1))
666 itemArr.emplace_back(std::move(ptr));
667 items.
add(itemArr.back().get());
669 it->setPosition (pos.x, pos.y, pos.z);
670 it->setDirection(dir.x, dir.y, dir.z);
679 if(itemInstance==
size_t(-1))
682 std::unique_ptr<Item> ptr;
683 if(itemInstance==ItLsTorchburning)
688 it->handle().owner = ownerNpc==size_t(-1) ? 0 : int32_t(ownerNpc);
689 itemArr.emplace_back(std::move(ptr));
690 items.
add(itemArr.back().get());
692 it->setObjMatrix(pos);
698 interactiveObj.
add(obj);
702 objStatic.push_back(obj);
709 rootVobs.emplace_back(std::move(p));
718 return interactiveObj.
hasObject(def) ? def :
nullptr;
731 return items.
hasObject(def) ? def :
nullptr;
735 if(def && testObj(*def,pl,opt))
742 if(def && testObj(*def,pl,opt))
744 if(owner.
view()==
nullptr)
753 if(testObj(n,pl,opt,nlen)){
767 if(def && testObj(*def,pl,xopt))
770 auto r = findObj(npcNear,pl,opt);
779 if(def && testObj(*def,pl,opt))
781 if(owner.
view()==
nullptr)
790 if(testObj(n,pl,opt,nlen)){
800 static bool ddraw=
false;
803 for(
auto& i:interactiveObj) {
805 m.mul(i->transform());
813 x = (0.5f*x+0.5f)*
float(p.
w);
814 y = (0.5f*y+0.5f)*
float(p.
h);
816 p.
setBrush(Tempest::Color(1,1,1,1));
817 p.
painter.drawRect(
int(x),int(y),1,1);
819 i->marchInteractives(p);
824 for(
auto& i:triggers)
825 if(
auto c =
dynamic_cast<CsCamera*
>(i)) {
831 const float dist=100*10.f;
835 if(i->checkMobName(dest))
839 float curDist=dist*dist;
841 if(i.isAvailable() && i.checkMobName(dest)) {
842 float d = pl.qDistTo(i);
861 for(
auto& i:routines) {
862 if(i.scheme==scheme) {
863 i.routines.push_back(r);
864 std::sort(i.routines.begin(),i.routines.end(),[](
const MobRoutine& l,
const MobRoutine& r){
865 return l.time<r.time;
872 st.routines.push_back(r);
873 routines.emplace_back(std::move(st));
885 sndPerc.push_back(m);
889 const auto pl = owner.
player();
902 for(
auto& ptr:npcNear) {
903 passivePerceptionProcess(r, *ptr, *pl);
920 if(distance > range*range)
926 if(msg.
other==
nullptr)
947 if(msg.
item!=
size_t(-1) && msg.
other!=
nullptr)
953 for(
auto& r:routines)
956 for(
auto& i:npcInvalid)
957 if(i->handlePtr().use_count()>1)
958 npcArr.push_back(std::move(i));
else
959 npcRemoved.push_back(std::move(i));
962 for(
size_t i=0;i<npcArr.size();) {
963 auto& n = *npcArr[i];
964 if(n.resetPositionToTA()){
967 npcInvalid.emplace_back(std::move(npcArr[i]));
968 npcArr.erase(npcArr.begin()+int(i));
971 auto&
npc = *npcInvalid.back();
977 for(
auto& i:routines) {
978 auto s = i.stateByTime(owner.
time());
981 for(
auto& i:interactiveObj) {
983 for(
auto& r:routines) {
984 if(i->schemeName()==r.scheme)
987 i->resetPositionToTA(state);
991void WorldObjects::setMobState(std::string_view scheme, int32_t st) {
992 for(
auto& i:rootVobs)
993 i->setMobState(scheme,st);
997static T&
deref(std::unique_ptr<T>& x){
return *x; }
1047auto WorldObjects::findObj(T &src,
const Npc &pl,
const SearchOpt& opt) ->
typename std::remove_reference<
decltype(src[0])>::type {
1048 typename std::remove_reference<
decltype(src[0])>::type ret=
nullptr;
1049 float rlen = opt.rangeMax*opt.rangeMax;
1050 if(owner.view()==
nullptr)
1058 if(testObj(n,pl,opt,nlen)){
1069 return testObj(src,pl,opt,rlen);
1076 const float plAng = pl.
rotationRad()+float(M_PI/2);
1077 const float ang = float(std::cos(
double(opt.
azi)*M_PI/180.0));
1080 if(
reinterpret_cast<void*
>(&
npc)==
reinterpret_cast<const void*
>(&pl))
1089 if(l>qmax || l<qmin)
1094 auto angle = std::atan2(dpos.z,dpos.x);
void setBrush(const Tempest::Brush &brush)
Tempest::Painter & painter
const Tempest::Matrix4x4 mvp
void invokeRefreshAtInsert(Npc &npc)
size_t findSymbolIndex(std::string_view s)
const PerDist & percRanges() const
void onWldItemRemoved(const Item &itm)
void setInstanceItem(Npc &holder, size_t itemId)
static auto options() -> const Options &
bool canSeeNpc(const Npc &npc, bool freeLos) const
bool overrideFocus() const
void setObjMatrix(const Tempest::Matrix4x4 &m)
const zenkit::IItem & handle() const
float qDistTo(const Tempest::Vec3 pos) const
auto weaponState() const -> WeaponState
auto currentTaPoint() const -> const WayPoint *
bool canSeeNpc(const Npc &oth, bool freeLos) const
float rotationRad() const
void setDirection(const Tempest::Vec3 &pos)
bool setPosition(float x, float y, float z)
auto interactive() const -> Interactive *
auto position() const -> Tempest::Vec3
bool isUnconscious() const
void attachToPoint(const WayPoint *p)
bool perceptionProcess(Npc &pl)
auto processPolicy() const -> NpcProcessPolicy
bool isTargetableBySpell(TargetType t) const
uint64_t percNextTime() const
bool canSeeItem(const Item &it, bool freeLos) const
void write(const Arg &... a)
bool setEntry(const Args &... args)
uint32_t directorySize(const Args &... args)
void setVersion(uint16_t v)
std::string_view worldName() const
bool hasObject(const T *v) const
void find(const Tempest::Vec3 &p, float R, const Func &f)
static std::unique_ptr< Vob > load(Vob *parent, World &world, const zenkit::VirtualObject &vob, Flags flags)
Tempest::Vec3 position() const
Tempest::Vec3 direction() const
static void parallelFor(T *b, T *e, const F &func)
static void parallelTasks(std::vector< T > &data, const F &func)
Item * validateItem(Item *def)
void addRoot(const std::shared_ptr< zenkit::VirtualObject > &vob, bool startup)
auto takeItem(Item &it) -> std::unique_ptr< Item >
void addInteractive(Interactive *obj)
void load(Serialize &fout)
void detectNpc(const float x, const float y, const float z, const float r, const std::function< void(Npc &)> &f)
CsCamera * currentCs() const
void tick(uint64_t dt, uint64_t dtPlayer)
Item * findItem(const Npc &pl, Item *def, const SearchOpt &opt)
void enableDefTrigger(AbstractTrigger &trigger)
void enableTicks(AbstractTrigger &t)
uint32_t itmId(const void *ptr) const
void addTrigger(AbstractTrigger *trigger)
void updateAnimation(uint64_t dt)
void setMobRoutine(gtime time, std::string_view scheme, int32_t state)
void detectItem(const float x, const float y, const float z, const float r, const std::function< void(Item &)> &f)
void runEffect(Effect &&e)
Npc * findNpcNear(const Npc &pl, Npc *def, const SearchOpt &opt)
void stopEffect(const VisualFx &vfx)
void invalidateVobIndex()
bool isTargeted(Npc &npc)
Interactive * findInteractive(const Npc &pl, Interactive *def, const SearchOpt &opt)
uint32_t npcId(const Npc *ptr) const
Bullet & shootBullet(const Item &itmId, const Tempest::Vec3 &pos, const Tempest::Vec3 &dir, float tgRange, float speed)
bool triggerOnStart(bool firstTime)
Interactive * validateInteractive(Interactive *def)
void marchInteractives(DbgPainter &p) const
uint32_t mobsiId(const void *ptr) const
Item * addItemDyn(size_t itemInstance, const Tempest::Matrix4x4 &pos, size_t owner)
void save(Serialize &fout)
void enableCollizionZone(CollisionZone &z)
const Npc & npc(size_t i) const
WorldObjects(World &owner)
Npc * insertPlayer(std::unique_ptr< Npc > &&npc, std::string_view at)
Npc * validateNpc(Npc *def)
Npc * addNpc(size_t itemInstance, std::string_view at)
void setCurrentCs(CsCamera *cs)
void sendPassivePerc(Npc &self, Npc &other, Npc *victim, Item *itm, int32_t perc)
void addStatic(StaticObj *obj)
void removeItem(Item &it)
size_t hasItems(std::string_view tag, size_t itemCls)
Npc * findNpcByInstance(size_t instance, size_t n=0)
void sendImmediatePerc(Npc &self, Npc &other, Npc &victim, Item *itm, int32_t perc)
auto takeNpc(const Npc *npc) -> std::unique_ptr< Npc >
void onItemRemoved(const Item &itm)
bool testFocusNpc(const Npc &pl, Npc *def, const SearchOpt &opt)
bool execTriggerEvent(const TriggerEvent &e)
void disableCollizionZone(CollisionZone &z)
void detectNpcNear(const std::function< void(Npc &)> &f)
Item * findItemByInstance(size_t instance, size_t n=0)
void triggerEvent(const TriggerEvent &e)
Interactive * availableMob(const Npc &pl, std::string_view name)
void disableTicks(AbstractTrigger &t)
Item * addItem(size_t itemInstance, std::string_view at)
void marchCsCameras(DbgPainter &p) const
uint64_t tickCount() const
const WayPoint * findPoint(std::string_view name, bool inexact=true) const
const WayPoint & deadPoint() const
const WayPoint * findFreePoint(const Npc &pos, std::string_view name) const
const WayPoint & startPoint() const
const WayPoint * findWayPoint(std::string_view name) const
const WayPoint * findNextPoint(const WayPoint &pos) const
GameScript & script() const
static CommandLine * instance
int at(PercType perc, int r) const
static bool checkTargetType(T &, TargetType)
static bool checkFlag(T &, WorldObjects::SearchFlg)
static bool canSee(const Npc &, const T &)
static T & deref(std::unique_ptr< T > &x)