diff --git a/game/game/gamescript.cpp b/game/game/gamescript.cpp index 1e9102e0..e38c87a9 100644 --- a/game/game/gamescript.cpp +++ b/game/game/gamescript.cpp @@ -3176,7 +3176,7 @@ void GameScript::snd_play3d(std::shared_ptr npcRef, std::string_vi c = char(std::toupper(c)); auto sfx = ::Sound(*owner.world(),::Sound::T_3D,file,npc->position(),0.f,false); sfx.play(); - owner.world()->sendPassivePerc(*npc,*npc,*npc,PERC_ASSESSQUIETSOUND); + owner.world()->sendImmediatePerc(*npc,*npc,*npc,PERC_ASSESSQUIETSOUND); } void GameScript::exitsession() { diff --git a/game/game/movealgo.cpp b/game/game/movealgo.cpp index 2d011551..a52c6765 100644 --- a/game/game/movealgo.cpp +++ b/game/game/movealgo.cpp @@ -434,7 +434,7 @@ void MoveAlgo::tick(uint64_t dt, MvFlags moveFlg) { portal = cache.sector; if(npc.isPlayer()) { auto& w = npc.world(); - w.sendPassivePerc(npc,npc,npc,PERC_ASSESSENTERROOM); + w.sendImmediatePerc(npc,npc,npc,PERC_ASSESSENTERROOM); } } } diff --git a/game/world/objects/npc.cpp b/game/world/objects/npc.cpp index 08377ffd..b384810a 100644 --- a/game/world/objects/npc.cpp +++ b/game/world/objects/npc.cpp @@ -2071,7 +2071,7 @@ void Npc::tickAnimationTags() { for(auto& i:ev.morph) visual.startMMAnim(*this,i.anim,i.node); if(ev.groundSounds>0 && isPlayer() && (bodyStateMasked()!=BodyState::BS_SNEAK)) - world().sendPassivePerc(*this,*this,*this,PERC_ASSESSQUIETSOUND); + world().sendImmediatePerc(*this,*this,*this,PERC_ASSESSQUIETSOUND); if(ev.def_opt_frame>0) commitDamage(); implSetFightMode(ev); @@ -3039,7 +3039,7 @@ Item* Npc::takeItem(Item& item) { return nullptr; it = addItem(std::move(ptr)); - if(isPlayer() && it!=nullptr) // && (it->handle().owner!=0 || it->handle().ownerGuild!=0)) + if(isPlayer() && it!=nullptr) owner.sendPassivePerc(*this,*this,*this,*it,PERC_ASSESSTHEFT); implAniWait(uint64_t(sq->totalTime())); @@ -4204,10 +4204,8 @@ bool Npc::canRayHitPoint(const Tempest::Vec3 pos, bool freeLos, float extRange) SensesBit Npc::canSenseNpc(const Npc &oth, bool freeLos, float extRange) const { const auto mid = oth.bounds().midTr; const auto st = oth.bodyStateMasked(); - /* Testing for BS_STAND as well, to avoid overreaction to monsters - * https://github.com/Try/OpenGothic/pull/589#issuecomment-2045897394 - */ - const bool isNoisy = (st!=BodyState::BS_SNEAK && st!=BodyState::BS_STAND); + // https://github.com/Try/OpenGothic/pull/589#issuecomment-2045897394 + const bool isNoisy = (st!=BodyState::BS_SNEAK && oth.isPlayer()); return canSenseNpc(mid,freeLos,isNoisy,extRange); } diff --git a/game/world/world.cpp b/game/world/world.cpp index 3c188a8a..2dcd89d7 100644 --- a/game/world/world.cpp +++ b/game/world/world.cpp @@ -667,11 +667,19 @@ Bullet& World::shootBullet(const Item &itm, const Npc &npc, const Npc *target, c } void World::sendPassivePerc(Npc &self, Npc &other, Npc &victum, int32_t perc) { - wobj.sendPassivePerc(self,other,victum,perc); + wobj.sendPassivePerc(self,other,victum,nullptr,perc); } -void World::sendPassivePerc(Npc &self, Npc &other, Npc &victum, Item &item, int32_t perc) { - wobj.sendPassivePerc(self,other,victum,item,perc); +void World::sendPassivePerc(Npc &self, Npc &other, Npc &victum, Item& item, int32_t perc) { + wobj.sendPassivePerc(self,other,victum,&item,perc); + } + +void World::sendImmediatePerc(Npc& self, Npc& other, Npc& victum, int32_t perc) { + wobj.sendImmediatePerc(self,other,victum,nullptr,perc); + } + +void World::sendImmediatePerc(Npc& self, Npc& other, Npc& victum, Item& item, int32_t perc) { + wobj.sendImmediatePerc(self,other,victum,&item,perc); } Sound World::addWeaponHitEffect(Npc& src, const Bullet* srcArrow, Npc& reciver) { diff --git a/game/world/world.h b/game/world/world.h index 570cc7dc..f4d31f9b 100644 --- a/game/world/world.h +++ b/game/world/world.h @@ -156,8 +156,11 @@ class World final { Bullet& shootBullet(const Item &itmId, const Npc& npc, const Npc* target, const Interactive* inter); Bullet& shootSpell(const Item &itm, const Npc &npc, const Npc *target); - void sendPassivePerc (Npc& self,Npc& other,Npc& victum,int32_t perc); - void sendPassivePerc (Npc& self,Npc& other,Npc& victum, Item& item,int32_t perc); + void sendPassivePerc (Npc& self, Npc& other, Npc& victum, int32_t perc); + void sendPassivePerc (Npc& self, Npc& other, Npc& victum, Item& item, int32_t perc); + + void sendImmediatePerc(Npc& self, Npc& other, Npc& victum, int32_t perc); + void sendImmediatePerc(Npc& self, Npc& other, Npc& victum, Item& item, int32_t perc); bool isInSfxRange(const Tempest::Vec3& pos) const; bool isInPfxRange(const Tempest::Vec3& pos) const; diff --git a/game/world/worldobjects.cpp b/game/world/worldobjects.cpp index 61a50556..ffca1fa3 100644 --- a/game/world/worldobjects.cpp +++ b/game/world/worldobjects.cpp @@ -868,27 +868,60 @@ void WorldObjects::setMobRoutine(gtime time, std::string_view scheme, int32_t st routines.emplace_back(std::move(st)); } -void WorldObjects::sendPassivePerc(Npc &self, Npc &other, Npc &victum, int32_t perc) { +void WorldObjects::sendPassivePerc(Npc &self, Npc &other, Npc &victum, Item* itm, int32_t perc) { PerceptionMsg m; m.what = perc; m.pos = self.position(); m.self = &self; m.other = &other; m.victum = &victum; - + if(itm!=nullptr) + m.item = itm->handle().symbol_index(); sndPerc.push_back(m); } -void WorldObjects::sendPassivePerc(Npc &self, Npc &other, Npc &victum, Item &itm, int32_t perc) { - PerceptionMsg m; - m.what = perc; - m.pos = self.position(); - m.self = &self; - m.other = &other; - m.victum = &victum; - m.item = itm.handle().symbol_index(); +void WorldObjects::sendImmediatePerc(Npc& self, Npc& other, Npc& victum, Item* itm, int32_t perc) { + const auto pl = owner.player(); + if(pl==nullptr || pl->bodyStateMasked()==BS_SNEAK) + return; - sndPerc.push_back(m); + PerceptionMsg r; + r.what = perc; + r.pos = self.position(); + r.self = &self; + r.other = &other; + r.victum = &victum; + if(itm!=nullptr) + r.item = itm->handle().symbol_index(); + + for(auto& ptr:npcNear) { + Npc& i = *ptr; + if(i.isPlayer() || i.isDead()) + continue; + + const uint64_t percNextTime = i.percNextTime(); + if(percNextTime<=owner.tickCount()) + i.perceptionProcess(*pl); + + if(i.processPolicy()!=Npc::AiNormal) + continue; + + if(r.self==&i) + continue; + + const float distance = i.qDistTo(r.pos); + const float range = float(owner.script().percRanges().at(PercType(r.what), i.handle().senses_range)); + + if(distance > range*range) + continue; + + if(i.isDown() || i.isPlayer()) + continue; + + if(r.item!=size_t(-1) && r.other!=nullptr) + owner.script().setInstanceItem(*r.other,r.item); + i.perceptionProcess(*r.other,r.victum,distance,PercType(perc)); + } } void WorldObjects::resetPositionToTA() { diff --git a/game/world/worldobjects.h b/game/world/worldobjects.h index 6fe0da9d..5890834b 100644 --- a/game/world/worldobjects.h +++ b/game/world/worldobjects.h @@ -126,8 +126,9 @@ class WorldObjects final { Interactive* availableMob(const Npc& pl, std::string_view name); void setMobRoutine(gtime time, std::string_view scheme, int32_t state); - void sendPassivePerc(Npc& self,Npc& other,Npc& victum,int32_t perc); - void sendPassivePerc(Npc& self,Npc& other,Npc& victum,Item& itm,int32_t perc); + void sendPassivePerc (Npc& self, Npc& other, Npc& victum, Item* itm, int32_t perc); + void sendImmediatePerc(Npc& self, Npc& other, Npc& victum, Item* itm, int32_t perc); + void resetPositionToTA(); private: