#include "precompile.h" #include "guide.h" #include "human.h" #include "room.h" #include "glmhelper.h" #include "hero.h" #include "trigger.h" #include "skill.h" #include "mt/GuideStep.h" #include "mt/Hero.h" #include "mt/Skill.h" void Guide::Init(Human* owner) { owner_ = owner; if (!owner_->room->IsNewBieRoom()) { return; } if (mt::GuideStep::_steps.empty()) { return; } curr_step_idx_ = 0; UpdateStep(); } void Guide::UpdateStep() { curr_step_meta_ = mt::GuideStep::_steps.at(curr_step_idx_); #ifdef DEBUG a8::XPrintf("UpdateStep idx:%d id:%d target:%d\n", { curr_step_idx_, curr_step_meta_->id(), curr_step_meta_->target() }); #endif owner_->room->frame_event.AddPropChg ( owner_->GetWeakPtrRef(), kPropGuideStep, curr_step_meta_->id(), 0, true); switch (curr_step_meta_->target()) { case mt::MOVE_TARGET_GUIDE_STEP: { ProcMoveTarget(); } break; case mt::PICKUP_GUIDE_STEP: { ProcPickup(); } break; case mt::KILL_ENEMY_GUIDE_STEP: { ProcKillEnemy(); } break; case mt::USE_SKILL_AND_KILL_ENEMY_GUIDE_STEP: { ProcUseSkillAndKillEnemy(); } break; case mt::USE_SKILL_GUIDE_STEP: { ProcUseSkill(); } break; default: { abort(); } break; } } void Guide::ProcMoveTarget() { owner_->room->xtimer.SetIntervalEx (1, [this] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { if (!curr_step_meta_->_params.empty()) { Position pos; pos.FromGlmVec3(std::get<1>(curr_step_meta_->_params.at(0))); if (owner_->GetPos().Distance2D2(pos) < 30) { NextStep(); owner_->room->xtimer.DeleteCurrentTimer(); } } else { NextStep(); } } }, &owner_->xtimer_attacher); } void Guide::ProcPickup() { if (curr_step_meta_->_params.empty()) { NextStep(); return; } auto context = A8_MAKE_ANON_STRUCT_SHARED ( std::vector loots; ); { int i = 0; for (auto& tuple : curr_step_meta_->_params) { int time = std::get<0>(tuple); glm::vec3 pos = std::get<1>(tuple); int equip_id = std::get<2>(tuple); context->loots.push_back(-1); owner_->room->xtimer.SetTimeoutEx ( time / FRAME_RATE_MS, [this, equip_id, pos, context, i ] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { context->loots[i] = owner_->room->CreateLoot ( equip_id, pos, 1, 1 ); if (context->loots[i] <= 0) { abort(); } } }, &owner_->xtimer_attacher); ++i; } } owner_->room->xtimer.SetIntervalEx (1, [this, context] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { bool done = true; for (int loot_uniid : context->loots) { if (loot_uniid == -1) { done = false; break; } if (owner_->room->GetEntityByUniId(loot_uniid)) { done = false; break; } } if (done) { NextStep(); owner_->room->xtimer.DeleteCurrentTimer(); } } }, &owner_->xtimer_attacher); } void Guide::ProcKillEnemy() { if (curr_step_meta_->_params.empty()) { NextStep(); return; } auto context = A8_MAKE_ANON_STRUCT_SHARED ( std::vector heros; ); { int i = 0; for (auto& tuple : curr_step_meta_->_params) { int time = std::get<0>(tuple); glm::vec3 pos = std::get<1>(tuple); int hero_id = std::get<2>(tuple); const mt::Hero* hero_meta = mt::Hero::GetById(hero_id); if (!hero_meta){ continue; } context->heros.push_back(-1); owner_->room->xtimer.SetTimeoutEx ( time / FRAME_RATE_MS, [this, hero_id, hero_meta, pos, context, i ] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { Hero* hero = owner_->room->CreateHero ( nullptr, hero_meta, pos, pos, 666 ); if (!hero) { abort(); } hero->SetHP(0.1f); context->heros[i] = hero->GetUniId(); } }, &owner_->xtimer_attacher); ++i; } } owner_->room->xtimer.SetIntervalEx (1, [this, context] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { bool done = true; for (int hero_uniid : context->heros) { if (hero_uniid <= 0) { done = false; break; } Entity* e = owner_->room->GetEntityByUniId(hero_uniid); if (e && e->IsEntityType(ET_Hero)) { Hero* hero = (Hero*)e; if (!hero->dead) { done = false; break; } } } if (done) { NextStep(); owner_->room->xtimer.DeleteCurrentTimer(); } } }, &owner_->xtimer_attacher); } void Guide::ProcUseSkillAndKillEnemy() { if (curr_step_meta_->_params.empty()) { NextStep(); return; } auto context = A8_MAKE_ANON_STRUCT_SHARED ( std::vector heros; std::vector> handlers; ); { int i = 0; for (auto& tuple : curr_step_meta_->_params) { int time = std::get<0>(tuple); glm::vec3 pos = std::get<1>(tuple); int hero_id = std::get<2>(tuple); const mt::Hero* hero_meta = mt::Hero::GetById(hero_id); if (!hero_meta){ continue; } context->heros.push_back(-1); owner_->room->xtimer.SetTimeoutEx ( time / FRAME_RATE_MS, [this, hero_id, hero_meta, pos, context, i ] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { Hero* hero = owner_->room->CreateHero ( nullptr, hero_meta, pos, pos, 666 ); if (!hero) { abort(); } hero->SetHP(0.1f); context->heros[i] = hero->GetUniId(); } }, &owner_->xtimer_attacher); ++i; } } owner_->room->xtimer.SetIntervalEx (1, [this, context] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { bool done = true; for (int hero_uniid : context->heros) { if (hero_uniid <= 0) { done = false; break; } Entity* e = owner_->room->GetEntityByUniId(hero_uniid); if (e && e->IsEntityType(ET_Hero)) { Hero* hero = (Hero*)e; if (!hero->dead) { done = false; break; } } } if (done) { NextStep(); owner_->room->xtimer.DeleteCurrentTimer(); } } }, &owner_->xtimer_attacher); context->handlers.push_back (owner_->GetTrigger()->AddListener ( kUseSkillEvent, [this, context] (const a8::Args& args) mutable { Skill* skill = args.Get(0); if (curr_step_meta_->_int_param1 == skill->meta->skill_id()) { NextStep(); owner_->GetTrigger()->RemoveEventHandlers(context->handlers); } }) ); } void Guide::ProcUseSkill() { auto context = A8_MAKE_ANON_STRUCT_SHARED ( std::vector> handlers; ); context->handlers.push_back (owner_->GetTrigger()->AddListener ( kUseSkillEvent, [this, context] (const a8::Args& args) mutable { Skill* skill = args.Get(0); if (curr_step_meta_->_int_param1 == skill->meta->skill_id()) { NextStep(); owner_->GetTrigger()->RemoveEventHandlers(context->handlers); } }) ); } void Guide::NextStep() { #ifdef DEBUG a8::XPrintf("next step %d\n", {curr_step_idx_}); #endif ++curr_step_idx_; if (curr_step_idx_ >= mt::GuideStep::_steps.size()) { owner_->room->frame_event.AddPropChg ( owner_->GetWeakPtrRef(), kPropGuideStep, -1, 0, true); return; } UpdateStep(); }