OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
animation.cpp
Go to the documentation of this file.
1#include "animation.h"
2
3#include <Tempest/Log>
4#include <cctype>
5
6#include "world/objects/npc.h"
8#include "world/world.h"
9
10#include "utils/string_frm.h"
11#include "resources.h"
12
13using namespace Tempest;
14
15static void setupTime(std::vector<uint64_t>& t0,const std::vector<int32_t>& inp,float fps){
16 t0.resize(inp.size());
17 for(size_t i=0;i<inp.size();++i){
18 t0[i] = uint64_t(float(inp[i])*1000.f/fps);
19 }
20 }
21
22static uint64_t frameClamp(int32_t frame,uint32_t first,uint32_t numFrames,uint32_t last) {
23 if(frame<int(first))
24 return 0;
25 if(frame>=int(first+numFrames))
26 return numFrames-1; //workaround for gin, water, milk
27 if(frame>int(last))
28 return last-first;
29 return uint64_t(frame)-first;
30 }
31
32Animation::Animation(zenkit::ModelScript& p, std::string_view name, const bool ignoreErrChunks) {
33 ref = std::move(p.aliases);
34
35 for(auto& ani : p.animations) {
36 auto& data = loadMAN(ani, std::string(name) + '-' + ani.name + ".MAN");
37 data.data->sfx = std::move(ani.sfx);
38 data.data->gfx = std::move(ani.sfx_ground);
39 data.data->events = std::move(ani.events);
40 data.data->mmStartAni = std::move(ani.morph);
41
42 data.data->pfx.resize(ani.pfx.size() + ani.pfx_stop.size());
43 for(size_t i=0; i<ani.pfx.size(); ++i) {
44 static_cast<zenkit::MdsParticleEffect&>(data.data->pfx[i]) = std::move(ani.pfx[i]);
45 }
46 for(size_t i=0; i<ani.pfx_stop.size(); ++i) {
47 auto& p = data.data->pfx[i + ani.pfx.size()];
48 p.index = ani.pfx_stop[i].index;
49 p.frame = ani.pfx_stop[i].frame;
50 p.pfxStop = true;
51 }
52
53 std::stable_sort(data.data->pfx.begin(), data.data->pfx.end(), [](const MdsParticleEffect& l, const MdsParticleEffect& r) {
54 return l.frame < r.frame;
55 });
56 }
57
58 for(auto& co : p.combinations) {
59 string_frm name(co.model, 1+(co.last_frame-1)/2);
60
61 bool found=false;
62 for(size_t r=0;r<sequences.size();++r) { // reverse search: expect to find animations right before aniComb
63 auto& i = sequences[sequences.size()-r-1];
64 if(i.askName==name) {
65 auto d = i.data;
66 sequences.emplace_back();
67 Animation::Sequence& ani = sequences.back();
68 ani.name = co.name;
69 ani.askName = co.model;
70 ani.layer = co.layer;
71 ani.flags = co.flags;
72 ani.blendIn = uint64_t(1000*co.blend_in);
73 ani.blendOut = uint64_t(1000*co.blend_out);
74 ani.next = std::move(co.next);
75 ani.data = d; // set first as default
76 ani.comb.resize(size_t(co.last_frame));
77 found=true;
78 break;
79 }
80 }
81
82 if(!found) {
83 Log::d("comb not found: ", co.name," -> ", co.model, "(", name, ")"); // error
84 }
85 }
86
87 mesh = std::move(p.meshes);
88 meshDef = std::move(p.skeleton);
89
90 setupIndex();
91 }
92
93const Animation::Sequence* Animation::sequence(std::string_view name) const {
94 if(sqHot!=nullptr && sqHot->name==name)
95 return sqHot;
96 auto it = std::lower_bound(sequences.begin(),sequences.end(),name,[](const Sequence& s,std::string_view n){
97 return s.name<n;
98 });
99
100 if(it!=sequences.end() && it->name==name) {
101 sqHot = &(*it);
102 return &(*it);
103 }
104 return nullptr;
105 }
106
107const Animation::Sequence *Animation::sequenceAsc(std::string_view name) const {
108 for(auto& i:sequences)
109 if(i.askName==name)
110 return &i;
111 return nullptr;
112 }
113
114void Animation::debug() const {
115 for(auto& i:sequences)
116 Log::d(i.name);
117 }
118
119std::string_view Animation::defaultMesh() const {
120 if(!meshDef.name.empty() && !meshDef.disable_mesh)
121 return meshDef.name;
122 return "";
123 }
124
125Animation::Sequence& Animation::loadMAN(const zenkit::MdsAnimation& hdr, std::string_view name) {
126 sequences.emplace_back(hdr,name);
127 auto& ret = sequences.back();
128 if(ret.data==nullptr) {
129 ret.data = std::make_shared<AnimData>();
130 Log::e("unable to load animation sequence: \"",name,"\"");
131 }
132 return ret;
133 }
134
135void Animation::setupIndex() {
136 for(auto& sq:sequences)
137 sq.data->setupEvents(sq.data->fpsRate);
138
139 for(auto& r:ref) {
140 Sequence ani;
141 for(auto& s:sequences)
142 if(s.askName==r.alias)
143 ani.data = s.data;
144
145 if(ani.data==nullptr) {
146 Log::d("alias not found: ",r.name," -> ",r.alias);
147 continue;
148 }
149
150 ani.name = r.name;
151 ani.layer = r.layer;
152 ani.flags = r.flags;
153 ani.blendIn = uint64_t(1000 * r.blend_in);
154 ani.blendOut = uint64_t(1000 * r.blend_out);
155 ani.reverse = r.direction != zenkit::AnimationDirection::FORWARD;
156 ani.next = r.next;
157 sequences.emplace_back(std::move(ani));
158 }
159 ref.clear();
160
161 for(auto& sq:sequences) {
162 for(auto& i:sq.name)
163 i = char(std::toupper(i));
164 for(auto& i:sq.next)
165 i = char(std::toupper(i));
166 }
167
168 std::sort(sequences.begin(),sequences.end(),[](const Sequence& a,const Sequence& b){
169 return a.name<b.name;
170 });
171
172 for(auto& s:sequences) {
173 if(s.comb.size()==0)
174 continue;
175 for(size_t i=0;i<s.comb.size();++i) {
176 string_frm name(s.askName, int(i+1));
177 s.comb[i] = sequenceAsc(name);
178 }
179 }
180
181 for(auto& i:sequences) {
182 if((i.next==i.askName && !i.next.empty()) || i.next==i.name)
183 i.animCls = Loop;
184 if(!i.data->defWindow.empty()) {
185 i.animCls = Transition;
186 i.next = "";
187 }
188
189 if(i.name.find("S_")==0)
190 i.shortName = &i.name[2];
191 if(i.name=="T_1HRUN_2_1H" || i.name=="T_BOWRUN_2_BOW" ||
192 i.name=="T_2HRUN_2_2H" || i.name=="T_CBOWRUN_2_CBOW" ||
193 i.name=="T_MAGRUN_2_MAG" || i.name=="T_FISTRUN_2_FIST")
194 i.next = "";
195 }
196
197 for(auto& i:sequences) {
198 i.nextPtr = sequence(i.next);
199 i.owner = this;
200 }
201 // for(auto& i:sequences)
202 // Log::i(i.name);
203 }
204
205
206Animation::Sequence::Sequence(const zenkit::MdsAnimation& hdr, std::string_view fname) {
207 const auto* entry = Resources::vdfsIndex().find(fname);
208 if(entry==nullptr)
209 return;
210
211 auto reader = entry->open_read();
212 zenkit::ModelAnimation p;
213 p.load(reader.get());
214
215 data = std::make_shared<AnimData>();
216 askName = hdr.name;
217 layer = hdr.layer;
218 flags = hdr.flags;
219 blendIn = uint64_t(1000*hdr.blend_in);
220 blendOut = uint64_t(1000*hdr.blend_out);
221 next = hdr.next;
222 reverse = hdr.direction != zenkit::AnimationDirection::FORWARD;
223
224 data->firstFrame = uint32_t(hdr.first_frame);
225 data->lastFrame = uint32_t(hdr.last_frame);
226
227
228 name = p.name;
229 layer = p.layer;
230 data->fpsRate = p.fps;
231 data->numFrames = p.frame_count;
232 data->nodeIndex = p.node_indices;
233 data->samples = p.samples;
234
235 setupMoveTr();
236 }
237
238bool Animation::Sequence::isFinished(uint64_t now, uint64_t sTime, uint16_t comboLen) const {
239 const uint64_t t = now-sTime;
240 if(comboLen<data->defHitEnd.size()) {
241 if(t>data->defHitEnd[comboLen])
242 return true;
243 }
244 return float(t)>totalTime();
245 }
246
248 return float(data->numFrames)*1000.f/data->fpsRate;
249 }
250
251float Animation::Sequence::atkTotalTime(uint16_t comboLen) const {
252 if(comboLen<data->defHitEnd.size()) {
253 uint64_t time = data->defHitEnd[comboLen];
254 return float(time);
255 }
256 return totalTime();
257 }
258
259bool Animation::Sequence::canInterrupt(uint64_t now, uint64_t sTime, uint16_t comboLen) const {
260 const uint16_t cId = uint16_t(comboLen*2u);
261 if(animCls==Animation::Transition) {
262 if(size_t(cId+1)<data->defWindow.size() && data->defWindow.size()>0 && !data->defHitEnd.empty()) {
263 return !((now-sTime)<=data->defWindow[cId+0]);
264 }
265 return false;
266 }
267
268 if(size_t(cId+1)<data->defWindow.size() && isInComboWindow(now-sTime,comboLen)) {
269 return false;
270 }
271 return true;
272 }
273
274bool Animation::Sequence::isInComboWindow(uint64_t t, uint16_t comboLen) const {
275 uint16_t id = uint16_t(comboLen*2u);
276 return (data->defWindow[id+0]<t && t<=data->defWindow[id+1]);
277 }
278
280 if(data->defParFrame.size()!=2)
281 return false;
282 return data->defParFrame[0]<=t && t<data->defParFrame[1];
283 }
284
285bool Animation::Sequence::isDefWindow(uint64_t t) const {
286 for(size_t i=0;i+1<data->defWindow.size();i+=2) {
287 if(data->defWindow[i+0]<=t && t<data->defWindow[i+1])
288 return true;
289 }
290 return false;
291 }
292
294 for(auto& e:data->events)
295 if(e.type == zenkit::MdsEventType::OPTIMAL_FRAME)
296 return true;
297 return false;
298 }
299
300bool Animation::Sequence::isPrehit(uint64_t sTime, uint64_t now) const {
301 auto& d = *data;
302 auto numFrames = d.numFrames;
303 if(numFrames==0)
304 return false;
305
306 int64_t frame = int64_t(float(now-sTime)*d.fpsRate/1000.f);
307
308 for(auto& e:data->events)
309 if(e.type == zenkit::MdsEventType::OPTIMAL_FRAME)
310 for(auto i : e.frames)
311 if(int64_t(i) > frame)
312 return true;
313 return false;
314 }
315
316bool Animation::Sequence::extractFrames(uint64_t& frameA,uint64_t& frameB,bool& invert,uint64_t barrier, uint64_t sTime, uint64_t now) const {
317 auto& d = *data;
318 auto numFrames = d.numFrames;
319 if(numFrames==0)
320 return false;
321
322 float fpsRate = d.fpsRate;
323 frameA = uint64_t(float(barrier-sTime)*fpsRate/1000.f);
324 frameB = uint64_t(float(now -sTime)*fpsRate/1000.f);
325
326 if(frameA==frameB)
327 return false;
328
329 if(animCls==Animation::Loop){
330 frameA%=numFrames;
331 frameB%=numFrames;
332 } else {
333 frameA = std::min<uint64_t>(frameA,numFrames);
334 frameB = std::min<uint64_t>(frameB,numFrames);
335 }
336
337 if(reverse) {
338 frameA = numFrames-frameA;
339 frameB = numFrames-frameB;
340 std::swap(frameA,frameB);
341 }
342
343 invert = (frameB<frameA);
344 if(invert)
345 std::swap(frameA,frameB);
346 return true;
347 }
348
349void Animation::Sequence::processSfx(uint64_t barrier, uint64_t sTime, uint64_t now, Npc* npc, Interactive* mob) const {
350 uint64_t frameA=0,frameB=0;
351 bool invert=false;
352 if(!extractFrames(frameA,frameB,invert,barrier,sTime,now))
353 return;
354
355 auto& d = *data;
356 for(auto& i:d.sfx) {
357 uint64_t fr = frameClamp(i.frame,d.firstFrame,d.numFrames,d.lastFrame);
358 if(((frameA<=fr && fr<frameB) ^ invert) || i.frame==int32_t(d.lastFrame)) {
359 if(npc!=nullptr)
360 npc->emitSoundEffect(i.name,i.range,i.empty_slot);
361 if(mob!=nullptr)
362 mob->emitSoundEffect(i.name,i.range,i.empty_slot);
363 }
364 }
365 if(npc!=nullptr && !npc->isInAir()) {
366 for(auto& i:d.gfx){
367 uint64_t fr = frameClamp(i.frame,d.firstFrame,d.numFrames,d.lastFrame);
368 if((frameA<=fr && fr<frameB) ^ invert)
369 npc->emitSoundGround(i.name, i.range, i.empty_slot);
370 }
371 }
372 }
373
374void Animation::Sequence::processPfx(uint64_t barrier, uint64_t sTime, uint64_t now, MdlVisual& visual, World& world) const {
375 if(data->pfx.empty())
376 return;
377
378 uint64_t frameA=0,frameB=0;
379 bool invert=false;
380 if(!extractFrames(frameA,frameB,invert,barrier,sTime,now))
381 return;
382
383 auto& d = *data;
384 if(invert) {
385 //NOTE: carefull with ordering, in new loop:
386 // first finish event of current frame, then start events of the next one
387 for(auto& i:d.pfx) {
388 uint64_t fr = frameClamp(i.frame,d.firstFrame,d.numFrames,d.lastFrame);
389 if(!(fr<frameB))
390 processPfx(i, visual, world);
391 }
392 for(auto& i:d.pfx) {
393 uint64_t fr = frameClamp(i.frame,d.firstFrame,d.numFrames,d.lastFrame);
394 if(!(frameA<=fr))
395 processPfx(i, visual, world);
396 }
397 } else {
398 for(auto& i:d.pfx) {
399 uint64_t fr = frameClamp(i.frame,d.firstFrame,d.numFrames,d.lastFrame);
400 if(frameA<=fr && fr<frameB)
401 processPfx(i, visual, world);
402 }
403 }
404 }
405
407 if(p.pfxStop) {
408 visual.stopEffect(p.index);
409 }
410 else if(!p.name.empty()) {
411 Effect e(PfxEmitter(world,p.name),p.position);
412 e.setActive(true);
413 visual.startEffect(world,std::move(e),p.index,false);
414 }
415 }
416
417void Animation::Sequence::processEvents(uint64_t barrier, uint64_t sTime, uint64_t now, EvCount& ev) const {
418 uint64_t frameA=0,frameB=0;
419 bool invert=false;
420 if(!extractFrames(frameA,frameB,invert,barrier,sTime,now))
421 return;
422
423 auto& d = *data;
424 float fpsRate = d.fpsRate;
425
426 for(auto& e:d.events) {
427 if(e.type == zenkit::MdsEventType::OPTIMAL_FRAME) {
428 for(auto i:e.frames) {
429 uint64_t fr = frameClamp(i,d.firstFrame,d.numFrames,d.lastFrame);
430 if((frameA<=fr && fr<frameB) ^ invert)
431 processEvent(e,ev,uint64_t(float(fr)*1000.f/fpsRate)+sTime);
432 }
433 } else {
434 uint64_t fr = frameClamp(e.frame,d.firstFrame,d.numFrames,d.lastFrame);
435 if((frameA<=fr && fr<frameB) ^ invert)
436 processEvent(e,ev,uint64_t(float(fr)*1000.f/fpsRate)+sTime);
437 }
438 }
439
440 for(auto& i:d.gfx){
441 uint64_t fr = frameClamp(i.frame,d.firstFrame,d.numFrames,d.lastFrame);
442 if((frameA<=fr && fr<frameB) ^ invert)
443 ev.groundSounds++;
444 }
445
446 for(auto& i:d.mmStartAni){
447 uint64_t fr = frameClamp(i.frame,d.firstFrame,d.numFrames,d.lastFrame);
448 if((frameA<=fr && fr<frameB) ^ invert) {
449 EvMorph e;
450 e.anim = i.animation;
451 e.node = i.node;
452 ev.morph.push_back(e);
453 }
454 }
455 }
456
457void Animation::Sequence::processEvent(const zenkit::MdsEventTag& e, Animation::EvCount &ev, uint64_t time) {
458 switch(e.type) {
459 case zenkit::MdsEventType::OPTIMAL_FRAME:
460 ev.def_opt_frame++;
461 break;
462 case zenkit::MdsEventType::SET_FIGHT_MODE:
463 ev.weaponCh = e.fight_mode;
464 break;
465 case zenkit::MdsEventType::ITEM_CREATE:
466 case zenkit::MdsEventType::ITEM_EXCHANGE:{
467 EvTimed ex;
468 ex.def = e.type;
469 ex.item = e.item;
470 ex.slot[0] = e.slot;
471 ex.time = time;
472 ev.timed.push_back(ex);
473 break;
474 }
475 case zenkit::MdsEventType::ITEM_INSERT:
476 case zenkit::MdsEventType::ITEM_REMOVE:
477 case zenkit::MdsEventType::ITEM_DESTROY:
478 case zenkit::MdsEventType::ITEM_PLACE: {
479 EvTimed ex;
480 ex.def = e.type;
481 ex.slot[0] = e.slot;
482 ex.time = time;
483 ev.timed.push_back(ex);
484 break;
485 }
486 case zenkit::MdsEventType::MUNITION_PLACE:
487 case zenkit::MdsEventType::MUNITION_REMOVE: {
488 EvTimed ex;
489 ex.def = e.type;
490 ex.slot[0] = e.slot;
491 ex.time = time;
492 ev.timed.push_back(ex);
493 break;
494 }
495 case zenkit::MdsEventType::MESH_SWAP: {
496 EvTimed ex;
497 ex.def = e.type;
498 ex.slot[0] = e.slot;
499 ex.slot[1] = e.slot2;
500 ex.time = time;
501 ev.timed.push_back(ex);
502 break;
503 }
504 case zenkit::MdsEventType::TORCH_DRAW:
505 case zenkit::MdsEventType::TORCH_INVENTORY:
506 case zenkit::MdsEventType::TORCH_DROP: {
507 EvTimed ex;
508 ex.def = e.type;
509 ex.slot[0] = e.slot;
510 ex.time = time;
511 ev.timed.push_back(ex);
512 break;
513 }
514 default:
515 break;
516 }
517 }
518
519Tempest::Vec3 Animation::Sequence::speed(uint64_t at, uint64_t dt) const {
520 auto a = translateXZ(at), b=translateXZ(at+dt); // note: at-dt vs at is more correct probably
521 Tempest::Vec3 f = b-a;
522
523 if(reverse)
524 return -f;
525 return f;
526 }
527
528Tempest::Vec3 Animation::Sequence::translateXZ(uint64_t at) const {
529 auto& d = *data;
530 uint32_t numFrames = d.numFrames;
531 if(numFrames==0 || d.tr.size()==0)
532 return Tempest::Vec3();
533
534 if(animCls==Transition && !isFly()){
535 uint64_t all=uint64_t(totalTime());
536 if(at>all)
537 at = all;
538 }
539
540 float fr = float(data->fpsRate*float(at))/1000.f;
541 float a = std::fmod(fr,1.f);
542 uint64_t frameA = uint64_t(fr);
543 uint64_t frameB = frameA+1;
544
545 auto mA = frameA/d.tr.size();
546 auto pA = d.tr[size_t(frameA%d.tr.size())];
547
548 auto mB = frameB/d.tr.size();
549 auto pB = d.tr[size_t(frameB%d.tr.size())];
550
551 pA += d.moveTr*float(mA);
552 pB += d.moveTr*float(mB);
553
554 Tempest::Vec3 p = pA + (pB-pA)*a;
555 return p;
556 }
557
558void Animation::Sequence::schemeName(char scheme[64]) const {
559 scheme[0] = '\0';
560 for(size_t i=0, r=0; i<name.size(); ++i) {
561 if(name[i]=='_') {
562 for(i++;i<name.size() && r<63;++i) {
563 if(name[i]=='_')
564 break;
565 scheme[r] = name[i];
566 ++r;
567 }
568 scheme[r] = '\0';
569 break;
570 }
571 }
572 }
573
574void Animation::Sequence::setupMoveTr() {
575 data->setupMoveTr();
576 }
577
579 size_t sz = nodeIndex.size();
580 if(sz==0)
581 return;
582
583 if(nodeIndex[0]!=0)
584 return;
585
586 if(0<samples.size() && sz<=samples.size()) {
587 auto& a = samples[0].position;
588 auto& b = samples[samples.size()-sz].position;
589 moveTr.x = b.x-a.x;
590 moveTr.y = b.y-a.y;
591 moveTr.z = b.z-a.z;
592
593 tr.resize(samples.size()/sz - 1);
594 for(size_t i=0, r=0; r<tr.size(); i+=sz,++r) {
595 auto& p = tr[r];
596 auto& bi = samples[i].position;
597 p.x = bi.x-a.x;
598 p.y = bi.y-a.y;
599 p.z = bi.z-a.z;
600 }
601 static const float eps = 0.4f;
602 for(auto& i:tr) {
603 if(std::fabs(i.x)<eps && std::fabs(i.y)<eps && std::fabs(i.z)<eps)
604 continue;
605 hasMoveTr = true;
606 break;
607 }
608 }
609
610 if(0<samples.size()){
611 translate.x = samples[0].position.x;
612 translate.y = samples[0].position.y;
613 translate.z = samples[0].position.z;
614 }
615 }
616
618 if(fpsRate<=0.f)
619 return;
620
621 int hasOptFrame = std::numeric_limits<int>::max();
622 for(size_t i=0; i<events.size(); ++i)
623 if(events[i].type==zenkit::MdsEventType::OPTIMAL_FRAME) {
624 hasOptFrame = std::min(hasOptFrame, events[i].frames[0]);
625 }
626
627 for(size_t i=0; i<events.size(); ++i)
628 if(events[i].type==zenkit::MdsEventType::OPTIMAL_FRAME && events[i].frames[0]!=hasOptFrame) {
629 events[i] = std::move(events.back());
630 events.pop_back();
631 }
632
633 for(auto& r:events) {
634 if(r.type==zenkit::MdsEventType::HIT_END)
635 setupTime(defHitEnd,r.frames,fpsRate);
636 if(r.type==zenkit::MdsEventType::PARRY_FRAME)
637 setupTime(defParFrame,r.frames,fpsRate);
638 if(r.type==zenkit::MdsEventType::COMBO_WINDOW)
639 setupTime(defWindow,r.frames,fpsRate);
640 }
641 }
static void setupTime(std::vector< uint64_t > &t0, const std::vector< int32_t > &inp, float fps)
Definition animation.cpp:15
static uint64_t frameClamp(int32_t frame, uint32_t first, uint32_t numFrames, uint32_t last)
Definition animation.cpp:22
Animation(zenkit::ModelScript &p, std::string_view name, bool ignoreErrChunks)
Definition animation.cpp:32
const Sequence * sequenceAsc(std::string_view name) const
void debug() const
const Sequence * sequence(std::string_view name) const
Definition animation.cpp:93
std::string_view defaultMesh() const
void setActive(bool e)
Definition effect.cpp:115
void emitSoundEffect(std::string_view sound, float range, bool freeSlot)
void startEffect(World &owner, Effect &&pfx, int32_t slot, bool noSlot)
void stopEffect(const VisualFx &vfx)
Definition npc.h:25
bool isInAir() const
Definition npc.cpp:1045
void emitSoundEffect(std::string_view sound, float range, bool freeSlot)
Definition npc.cpp:2946
void emitSoundGround(std::string_view sound, float range, bool freeSlot)
Definition npc.cpp:2951
static const zenkit::Vfs & vdfsIndex()
Definition world.h:31
void setupEvents(float fpsRate)
zenkit::MdsFightMode weaponCh
Definition animation.h:37
uint8_t groundSounds
Definition animation.h:36
std::vector< EvMorph > morph
Definition animation.h:39
std::vector< EvTimed > timed
Definition animation.h:38
uint8_t def_opt_frame
Definition animation.h:35
std::string_view node
Definition animation.h:30
std::string_view anim
Definition animation.h:31
std::string_view slot[2]
Definition animation.h:25
std::string_view item
Definition animation.h:24
zenkit::MdsEventType def
Definition animation.h:23
float atkTotalTime(uint16_t comboLen) const
std::string next
Definition animation.h:112
float totalTime() const
bool canInterrupt(uint64_t now, uint64_t sTime, uint16_t comboLen) const
bool isAttackAnim() const
void processPfx(uint64_t barrier, uint64_t sTime, uint64_t now, MdlVisual &visual, World &world) const
bool isDefParWindow(uint64_t t) const
Tempest::Vec3 speed(uint64_t at, uint64_t dt) const
bool isFinished(uint64_t now, uint64_t sTime, uint16_t comboLen) const
Tempest::Vec3 translateXZ(uint64_t at) const
bool isPrehit(uint64_t sTime, uint64_t now) const
void schemeName(char buf[64]) const
zenkit::AnimationFlags flags
Definition animation.h:106
std::string name
Definition animation.h:103
void processEvents(uint64_t barrier, uint64_t sTime, uint64_t now, EvCount &ev) const
bool isInComboWindow(uint64_t t, uint16_t comboLen) const
void processSfx(uint64_t barrier, uint64_t sTime, uint64_t now, Npc *npc, Interactive *mob) const
std::vector< const Sequence * > comb
Definition animation.h:116
bool isDefWindow(uint64_t t) const
std::string askName
Definition animation.h:103
std::shared_ptr< AnimData > data
Definition animation.h:117