13using namespace Tempest;
16 :skInst(std::make_unique<
Pose>()) {
27 fout.
write(std::string(
""));
45 skInst->load(fin,solver);
47 rebindAttaches(*skeleton);
52 skInst->load(fin,solver);
54 rebindAttaches(*skeleton);
62 skInst->setSkeleton(v);
76 implSetBody(
nullptr,owner,std::move(body),0);
81 bind(head,std::move(h),
"BIP01 HEAD");
82 implSetBody(&npc,npc.
world(),std::move(body),version);
83 head.view.setAsGhost(hnpcFlagGhost);
84 head.view.setFatness(npc.
fatness());
111 implSetBody(&npc,npc.
world(),std::move(a),version);
119 implSetBody(&npc,npc.
world(),std::move(armor),-1);
125 if(
auto p = body.protoMesh()) {
126 for(
auto& att:p->attach) {
129 setSlotAttachment(std::move(view),att.name);
134 view = std::move(body);
136 view.
setFatness(npc==
nullptr ? 0 : npc->fatness());
139 hnpcVisual.view.setMesh(&view);
142void MdlVisual::setSlotAttachment(
MeshObjects::Mesh&& itm, std::string_view bone) {
143 if(bone.empty() || skeleton==
nullptr)
146 size_t id = skeleton->
findNode(bone);
150 for(
auto& i:attach) {
152 i.view=std::move(itm);
159 slt.bone = skeleton->
nodes[id].name;
160 bind(slt,std::move(itm),slt.bone);
161 attach.push_back(std::move(slt));
165 bind(sword,std::move(s),
"ZS_RIGHTHAND");
169 bind(bow,std::move(b),
"ZS_BOW");
173 bind(shield,std::move(s),
"ZS_SHIELD");
177 bind(ammunition,std::move(a),bone);
181 auto n = std::move(pfx.view);
186 pfx.view = std::move(spell);
187 pfx.view.setLooped(
true);
188 pfx.view.setPhysicsDisable();
189 if(skeleton!=
nullptr)
190 pfx.view.bindAttaches(*skInst,*skeleton);
194 pfx.view.setKey(owner,key,keyLvl);
198 if(bone.empty() || skeleton==
nullptr)
201 size_t id = skeleton->
findNode(bone);
206 if(
id==head.boneId && !head.view.isEmpty())
211 i.view=std::move(itm);
218 slt.bone = skeleton->
nodes[id].name;
219 bind(slt,std::move(itm),slt.bone);
220 item.push_back(std::move(slt));
225 bind(stateItm,std::move(a),bone);
230 size_t id = skeleton==
nullptr ? size_t(-1) : skeleton->
findNode(bone);
232 for(
size_t i=0;i<item.size();++i) {
233 if(
id==
size_t(-1) || item[i].boneId==
id) {
234 item[i] = std::move(item.back());
246 case zenkit::MdsFightMode::INVALID:
248 case zenkit::MdsFightMode::NONE:
251 case zenkit::MdsFightMode::FIST:
254 case zenkit::MdsFightMode::SINGLE_HANDED:
257 case zenkit::MdsFightMode::DUAL_HANDED:
260 case zenkit::MdsFightMode::BOW:
263 case zenkit::MdsFightMode::CROSSBOW:
266 case zenkit::MdsFightMode::MAGIC:
275 MeshAttach* att = &sword;
276 auto&
pose = *skInst;
294 auto it = npc.
world().addItemDyn(itm->
clsId(),p,npc.
handle().symbol_index());
301 MeshAttach* att = &sword;
302 auto&
pose = *skInst;
315 auto it = npc.
world().addItemDyn(itm->
clsId(),p,npc.
handle().symbol_index());
322 uint64_t timeUntil = vfx.effectPrefferedTime();
326 if(skeleton==
nullptr)
330 vfx.setBullet(
nullptr,owner);
332 for(
auto& i:effects) {
333 if(i.id==slot && !i.noSlot) {
334 i.timeUntil = timeUntil;
335 i.view = std::move(vfx);
336 i.view.bindAttaches(*skInst,*skeleton);
344 slt.timeUntil = timeUntil;
346 slt.view = std::move(vfx);
347 slt.view.bindAttaches(*skInst,*skeleton);
348 effects.push_back(std::move(slt));
353 for(
size_t i=0;i<effects.size();++i) {
354 if(effects[i].view.is(vfx)) {
355 effects[i] = std::move(effects.back());
364 for(
size_t i=0;i<effects.size();++i) {
365 if(effects[i].
id==slot) {
366 effects[i] = std::move(effects.back());
375 if(hnpcVisualName!=s) {
379 hnpcVisual.view =
Effect();
383 if(skeleton!=
nullptr)
384 hnpcVisual.view.bindAttaches(*skInst,*skeleton);
385 hnpcVisual.view.setActive(
true);
386 hnpcVisual.view.setLooped(
true);
387 hnpcVisual.view.setMesh(&view);
390 const bool nextGhost = (flags & zenkit::NpcFlag::GHOST);
391 if(hnpcFlagGhost!=nextGhost) {
392 hnpcFlagGhost=nextGhost;
394 head.view.setAsGhost(hnpcFlagGhost);
396 i.view.setAsGhost(hnpcFlagGhost);
402 head.view.setFatness(fatness);
404 i.view.setFatness(fatness);
408 auto& world = source.
world();
410 auto&
pose = *skInst;
415 auto src = source.
inventory().activeWeapon();
416 auto dst = dest .
inventory().activeWeapon();
418 if(src==
nullptr || dst==
nullptr)
434 skInst->setObjectMatrix(m,syncAttach);
441 skInst->setHeadRotation(dx,dz);
446 return skInst->headRotation();
452 bind(sword,
"ZS_RIGHTHAND");
454 bool twoHands = weapon!=
nullptr && weapon->
is2H();
455 bind(sword,twoHands ?
"ZS_LONGSWORD" :
"ZS_SWORD");
460 bind(bow,
"ZS_LEFTHAND");
else
461 bind(bow,
"ZS_RIGHTHAND");
463 bool cbow = range!=
nullptr && range->
isCrossbow();
464 bind(bow,cbow ?
"ZS_CROSSBOW" :
"ZS_BOW");
479 if(torchId==
size_t(-1))
482 auto hitem = std::make_shared<zenkit::IItem>();
485 torch.view->setVisual(*hitem,owner,
false);
486 torch.boneId = (skeleton==
nullptr ? size_t(-1) : skeleton->
findNode(
"ZS_LEFTHAND"));
488 auto&
pose = *skInst;
492 torch.view->setObjMatrix(p);
496 return torch.view!=
nullptr;
502 auto pos3 = Vec3{pos.at(3,0), pos.at(3,1), pos.at(3,2)};
511 for(
size_t i=0;i<effects.size();) {
512 if(effects[i].timeUntil<tickCount) {
513 effects[i] = std::move(effects.back());
516 effects[i].view.tick(dt);
523 const bool changed =
pose.
update(tickCount, force);
544 if(boneId==
size_t(-1))
545 return {pos.at(3,0), pos.at(3,1), pos.at(3,2)};
548 return {mat.at(3,0), mat.at(3,1), mat.at(3,2)};
553 return mapBone(ammunition.boneId);
556 return {pos.at(3,0), pos.at(3,1), pos.at(3,2)};
561 return {pos.at(3,0), pos.at(3,1)+180, pos.at(3,2)};
566 skInst->stopAnim(anim);
570 if(!skInst->hasAnim())
575 if(!skInst->stopItemStateAnim(solver,npc.
world().tickCount()))
577 if(!skInst->hasAnim())
583 return solver.
solveFrm(scheme)!=
nullptr;
587 skInst->stopWalkAnim();
588 if(!skInst->hasAnim())
593 return skInst->isStanding();
605 if(skInst->startAnim(solver,sq,0,
BS_NONE,hint,tickCount)) {
641 skInst->stopAllAnim();
649 bool forceAnim=
false;
653 skInst->stopAllAnim();
759 if(skInst->startAnim(solver,sq,comb,bs,hint,npc.
world().tickCount()))
792 if(skeleton!=
nullptr)
794 return {0.f,0.f,0.f};
799 if(
nullptr!=skeleton) {
800 size_t nodeId = skeleton->
findNode(
"BIP01");
801 if(nodeId!=
size_t(-1))
804 float rx = p.at(2,0);
805 float rz = p.at(2,2);
806 return float(std::atan2(rz,rx)) * 180.f / float(M_PI);
813 if(
auto ret = skInst->continueCombo(solver,sq,bs,npc.
world().tickCount()))
820 return skInst->comboLength();
825 if(!head.view.isEmpty())
826 b.
assign(b,head.view.bounds());
830void MdlVisual::bind(MeshAttach& slot,
MeshObjects::Mesh&& itm, std::string_view bone) {
831 slot.boneId = skeleton==
nullptr ? size_t(-1) : skeleton->findNode(bone);
832 slot.view = std::move(itm);
837void MdlVisual::bind(PfxAttach& slot,
Effect&& itm, std::string_view bone) {
838 slot.boneId = skeleton==
nullptr ? size_t(-1) : skeleton->findNode(bone);
839 slot.view = std::move(itm);
845void MdlVisual::bind(Attach<View>& slot, std::string_view bone) {
846 slot.boneId = skeleton==
nullptr ? size_t(-1) : skeleton->findNode(bone);
851void MdlVisual::rebindAttaches(
const Skeleton& to) {
852 auto mesh = {&head,&sword,&bow,&ammunition,&stateItm};
854 rebindAttaches(*i,to);
856 rebindAttaches(i,to);
858 rebindAttaches(i,to);
860 i.view.bindAttaches(*skInst,to);
861 pfx.view.bindAttaches(*skInst,to);
862 hnpcVisual.view.bindAttaches(*skInst,to);
866void MdlVisual::rebindAttaches(Attach<View>& mesh,
const Skeleton& to) {
867 if(mesh.bone.empty())
868 mesh.boneId = size_t(-1);
else
869 mesh.boneId = to.
findNode(mesh.bone);
873 MdlVisual::MeshAttach* mesh[] = {&head, &sword,&shield,&bow,&ammunition,&stateItm};
880 for(
auto& i:effects) {
881 i.view.setObjMatrix(pos);
884 pfx.view.setObjMatrix(pos);
885 hnpcVisual.view.setObjMatrix(pos);
886 if(torch.view!=
nullptr) {
887 auto&
pose = *skInst;
891 torch.view->setObjMatrix(p);
900 if(skeleton==
nullptr)
902 auto ret = skeleton->
name();
903 auto end = ret.find_first_of(
"._");
904 return ret.substr(0, end);
909 if(att.view.isEmpty())
911 auto&
pose = *skInst;
915 att.view.setObjMatrix(p);
919 return skInst->setAnimItem(solver,npc,scheme,state);
939 const int id = std::rand()%count + 1;
942 std::snprintf(name,
sizeof(name),
"T_DIALOGGESTURE_%02d",
id);
951 MdlVisual::MeshAttach* mesh[] = {&head,&sword,&shield,&bow,&ammunition,&stateItm};
955 i->view.startMMAnim(anim,1,uint64_t(-1));
960 if(duration!=uint64_t(-1) && duration!=0)
961 duration += npc.
world().tickCount();
962 head.view.startMMAnim(anim,intensity,duration);
967 for(uint16_t i=0; i<count; i++){
969 std::snprintf(buf,
sizeof(buf),
"T_DIALOGGESTURE_%02d",i+1);
970 skInst->stopAnim(buf);
void addOverlay(const Skeleton *sk, uint64_t time)
const Animation::Sequence * solveFrm(std::string_view format) const
void load(Serialize &fin)
const Animation::Sequence * solveAnim(Anim a, WeaponState st, WalkBit wlk, const Pose &pose) const
void setSkeleton(const Skeleton *sk)
void delOverlay(std::string_view sk)
void update(uint64_t tickCount)
void save(Serialize &fout) const
bool hasOverlay(const Skeleton *sk) const
void assign(const Tempest::Vec3 &cen, float sizeSz)
size_t findSymbolIndex(std::string_view s)
void initializeInstanceItem(const std::shared_ptr< zenkit::IItem > &item, size_t instance)
auto version() const -> const VersionInfo &
auto loadVisualFx(std::string_view name) -> const VisualFx *
std::string_view visualSkeletonScheme() const
void setMagicWeaponKey(World &owner, SpellFxKey key, int32_t keyLvl=0)
bool hasAnim(std::string_view scheme) const
void setArmor(Npc &npc, MeshObjects::Mesh &&armor)
void setBody(Npc &npc, MeshObjects::Mesh &&body, const int32_t version)
void processLayers(World &world)
void stopDlgAnim(Npc &npc)
bool isUsingTorch() const
void setHeadRotation(float dx, float dz)
auto mapBone(const size_t boneId) const -> Tempest::Vec3
void stopAnim(Npc &npc, std::string_view anim)
void setVisualBody(World &owner, MeshObjects::Mesh &&body)
const Skeleton * visualSkeleton() const
void stopWalkAnim(Npc &npc)
auto mapWeaponBone() const -> Tempest::Vec3
void startEffect(World &owner, Effect &&pfx, int32_t slot, bool noSlot)
uint16_t comboLength() const
void setAmmoItem(MeshObjects::Mesh &&ammo, std::string_view bone)
float viewDirection() const
void setObjMatrix(const Tempest::Matrix4x4 &m, bool syncAttach=false)
void clearSlotItem(std::string_view bone)
void setNpcEffect(World &owner, Npc &npc, std::string_view s, zenkit::NpcFlag flags)
const Animation::Sequence * startAnimItem(Npc &npc, std::string_view scheme, int state)
bool startAnim(Npc &npc, WeaponState st)
const Animation::Sequence * startAnimAndGet(std::string_view name, uint64_t tickCount, bool forceAnim=false)
void save(Serialize &fout, const Npc &npc) const
void setSword(MeshObjects::Mesh &&sword)
void setSlotItem(MeshObjects::Mesh &&itm, std::string_view bone)
bool updateAnimation(Npc *npc, Interactive *mobsi, World &world, uint64_t dt, bool force)
bool startAnimDialog(Npc &npc)
void delOverlay(std::string_view sk)
auto mapHeadBone() const -> Tempest::Vec3
void setVisual(const Skeleton *visual)
void setStateItem(MeshObjects::Mesh &&itm, std::string_view bone)
void setYTranslationEnable(bool e)
bool setToFightMode(const WeaponState ws)
Tempest::Vec3 displayPosition() const
const Pose & pose() const
void setRangedWeapon(MeshObjects::Mesh &&bow)
void setShield(MeshObjects::Mesh &&shield)
bool setFightMode(zenkit::MdsFightMode mode)
bool processEvents(World &world, uint64_t &barrier, Animation::EvCount &ev)
void dropShield(Npc &owner)
Tempest::Vec2 headRotation() const
void addOverlay(const Skeleton *sk, uint64_t time)
void setAnimWhirl(Npc &npc, int dir)
void stopEffect(const VisualFx &vfx)
bool stopItemStateAnim(Npc &npc)
const Animation::Sequence * startAnimSpell(Npc &npc, std::string_view scheme, bool invest)
const Animation::Sequence * continueCombo(Npc &npc, AnimationSolver::Anim a, BodyState bs, WeaponState st, WalkBit wlk)
void load(Serialize &fin, Npc &npc)
void setAnimRotate(Npc &npc, int dir)
void updateWeaponSkeleton(const Item *sword, const Item *bow)
bool hasOverlay(const Skeleton *sk) const
bool isAnimExist(std::string_view name) const
void setMagicWeapon(Effect &&spell, World &owner)
void startFaceAnim(Npc &npc, std::string_view anim, float intensity, uint64_t duration)
void dropWeapon(Npc &owner)
void startMMAnim(Npc &npc, std::string_view anim, std::string_view node)
void emitBlockEffect(Npc &dst, Npc &src)
void setTorch(bool t, World &owner)
void setPose(const Tempest::Matrix4x4 &obj, const Pose &p)
void setSkeleton(const Skeleton *sk)
BodyState bodyState() const
void setVisual(std::string_view visual)
auto inventory() const -> const Inventory &
auto interactive() const -> Interactive *
Item * currentMeleeWeapon()
void delItem(size_t id, uint32_t amount)
auto processPolicy() const -> NpcProcessPolicy
Item * currentRangedWeapon()
BodyState bodyStateMasked() const
bool update(uint64_t tickCount, bool force)
void setObjectMatrix(const Tempest::Matrix4x4 &obj, bool sync)
void processLayers(AnimationSolver &solver, uint64_t tickCount)
auto bone(size_t id) const -> const Tempest::Matrix4x4 &
void processPfx(MdlVisual &visual, World &world, uint64_t tickCount)
bool processEvents(uint64_t &barrier, uint64_t now, Animation::EvCount &ev) const
void processSfx(Npc &npc, uint64_t tickCount)
void write(const Arg &... a)
size_t findNode(std::string_view name, size_t def=size_t(-1)) const
std::vector< Node > nodes
std::string_view name() const
float colisionHeight() const
MeshObjects::Mesh addAtachView(const ProtoMesh::Attach &visual, const int32_t version)
uint64_t tickCount() const
Sound addWeaponBlkEffect(ItemMaterial src, ItemMaterial reciver, const Tempest::Matrix4x4 &pos)
bool isInSfxRange(const Tempest::Vec3 &pos) const
bool isInPfxRange(const Tempest::Vec3 &pos) const
GameScript & script() const