bool AIIdea::CanUseCharacter(const Character & character) { if (character.IsDead()) return false; bool can_change_character = GameMode::GetInstance()->AllowCharacterSelection() && (Game::GetInstance()->ReadState() == Game::PLAYING) && !Game::GetInstance()->IsCharacterAlreadyChosen(); return (character.IsActiveCharacter() || can_change_character); }
//---------------------------------------------------------------------------- void GroupBuf::Update (double appSeconds, double elapsedSeconds) { Buf::Update(appSeconds, elapsedSeconds); Scene *scene = PX2_PROJ.GetScene(); Character *targetChar = DynamicCast<Character>(scene->GetActorByID(mToGroupCharacterID)); if (targetChar) { mCharacter->SetGroup(targetChar->GetGroup()); if (targetChar->IsDead() || targetChar->IsFreezed()) SetOver(true); } else { SetOver(true); } }
void Suicide::Refresh() { // The suicide sound may play at different speed for different players, // that's why the explosion should not depend on the fact if the sound has finished playing or not. uint time_since_last_fire = Time::GetInstance()->Read() - m_last_fire_time; Character *player = &ActiveCharacter(); if (m_last_fire_time > 0 && time_since_last_fire > SUICIDE_SOUND_DURATION_IN_MS && !player->IsDead()) { player->DisableDeathExplosion(); player->body->MakeParticles(ActiveCharacter().GetPosition()); player->SetEnergy(0, player); // Die! ApplyExplosion(player->GetCenter(), cfg()); } }
//---------------------------------------------------------------------------- bool Skill::Activate() { Scene *scene = PX2_PROJ.GetScene(); if (!scene) return false; if (!mCharacter) return false; if (!mFirstSkillStep) return false; if (mActivateAllowTimes >= 0) { if (mActivatedTimes >= mActivateAllowTimes) return false; } if (IsOnCD()) return false; SkillController *skillComp = DynamicCast<SkillController>( mCharacter->GetControllerByName("SkillController")); if (skillComp) { assertion(false, "has no this component."); return false; } mIsActivatting = true; SetOnCD(true); SetOnCDTime(0.0f); float randomVal = Mathf::UnitRandom(); if (randomVal > mActivateProbability) return true; mActivatedTimes++; const APoint &curPos = mCharacter->LocalTransform.GetTranslate(); const AVector &faceDir = mCharacter->GetHeading(); int aimTarget = skillComp->GetAimTarget(); Character *aimChar = skillComp->GetAimTargetCharacter(); int group = mCharacter->GetGroup(); float radiusLength = GetMRadiusLength(); float width = GetMWidth(); float degree = GetMFanDegree(); ShapeType shapeType = GetShapeType(); int numRangeLock = GetNumRangeLock(); AffectGroupType agt = GetAffectGroupType(); if (NFT_NEAR == mNearFarType) { SkillInstance *inst = new0 SkillInstance(this); mSkillInstances.push_back(inst); int numAdded = 0; inst->SetAimTarget(aimTarget); if (IsRangeType()) // ·¶Ξ§ { if (-1 == numRangeLock) { std::vector<Actor*> actors; scene->GetRangeActors(actors, curPos, radiusLength, true, GetSkillQueryBitSet()); for (int i = 0; i < (int)actors.size(); i++) { Character *character = DynamicCast<Character>(actors[i]); if (character && !character->IsDead()) { const APoint &targetPos = character->LocalTransform.GetTranslate(); float targetRadius = character->GetRadius(); if (IsInRange(curPos, radiusLength, width, faceDir, degree, targetPos, targetRadius, shapeType, false)) { inst->AddTarget(character->GetID()); numAdded++; } } } } else if (numRangeLock > 0) { if (AGT_SELF == agt) { inst->AddTarget(mCharacter->GetID()); numAdded++; } std::vector<Actor*> actors; scene->GetRangeActors(actors, curPos, radiusLength, true, GetSkillQueryBitSet()); for (int i = 0; i < (int)actors.size(); i++) { Character *character = DynamicCast<Character>(actors[i]); if (character && !character->IsDead() && character != aimChar && character != mCharacter) { if ((AGT_ENEMYS == agt && character->GetGroup() != group) || (AGT_SELF_GROUP==agt) && character->GetGroup()==group || (AGT_SELF == agt && character->GetGroup() == group) || (AGT_BOTH == agt)) { const APoint &targetPos = character->LocalTransform.GetTranslate(); float targetRadius = character->GetRadius(); if (IsInRange(curPos, radiusLength, width, faceDir, degree, targetPos, targetRadius, shapeType, false) && numAdded < numRangeLock) { inst->AddTarget(character->GetID()); numAdded++; } } } } } } else // µ¥Με { if (AGT_ENEMYS == agt || AGT_BOTH == agt) { Character *aimChar = skillComp->GetAimTargetCharacterAlive(); if (aimChar && aimChar->IsContainAllBits(GetSkillQueryBitSet())) { const APoint &targetPos = aimChar->LocalTransform.GetTranslate(); float targetRadius = aimChar->GetRadius(); if (IsInRange(curPos, radiusLength, width, faceDir, degree, targetPos, targetRadius, shapeType, false)) { inst->AddTarget(aimChar->GetID()); numAdded++; } } } else if (AGT_SELF == agt) { inst->AddTarget(mCharacter->GetID()); numAdded++; } } inst->Enter(mFirstSkillStep); } else { int multiAdd = 0; if (1 == mNumMultiInstance) { SkillInstance *inst = new0 SkillInstance(this); mSkillInstances.push_back(inst); inst->SetAimTarget(aimTarget); inst->Enter(mFirstSkillStep); multiAdd++; } else if (mNumMultiInstance > 1) { std::vector<Actor*> actors; scene->GetRangeActors(actors, curPos, radiusLength, true, GetSkillQueryBitSet()); SkillInstance *inst = new0 SkillInstance(this); mSkillInstances.push_back(inst); if (AGT_ENEMYS == this->GetAffectGroupType()) { inst->SetAimTarget(aimTarget); } else if (AGT_SELF == this->GetAffectGroupType()) { inst->SetAimTarget(mCharacter->GetID()); } inst->Enter(mFirstSkillStep); multiAdd++; for (int i = 0; i < (int)actors.size(); i++) { Character *character = DynamicCast<Character>(actors[i]); if (character && !character->IsDead() && character != aimChar && character != mCharacter) { SkillInstance *inst1 = new0 SkillInstance(this); mSkillInstances.push_back(inst1); inst1->SetAimTarget(character->GetID()); inst->SetBeShared(true); inst1->Enter(mFirstSkillStep); multiAdd++; } if (multiAdd >= mNumMultiInstance) break; } } } return true; }
void Chapter::Do(Character& character) const { if (m_verbose) { std::clog << __func__ << std::endl; } Helper h; assert(m_observer); character.SetObserver(m_observer); if (m_verbose) { std::clog << "The first text comes now" << std::endl; } ShowText("\n"); #ifndef NDEBUG ShowText("CHAPTER " + h.ToStr(GetChapterNumber()) + "\n"); #endif //Display the text line by line ShowText(m_text + "\n"); if (m_verbose) { std::clog << "The first text has been" << std::endl; } if (GetType() == ChapterType::game_lost) { m_game_lost_chapter.Do(character); assert(character.IsDead()); return; } else if (GetType() == ChapterType::game_won) { ShowText("\n"); m_game_won_chapter.Do(character); ShowText("\n"); return; } else if (GetType() == ChapterType::play_dice) { m_dice_game_chapter.Do(character); m_consequence.Apply(character); } else if (GetType() == ChapterType::play_ball) { m_ball_game_chapter.Do(character); m_consequence.Apply(character); } else if (GetType() == ChapterType::play_pill) { m_pill_game_chapter.Do(character); if (character.IsDead()) return; m_consequence.Apply(character); } //Options else if (!GetOptions().GetOptions().empty()) { if (GetOptions().GetValidOptions(character).empty()) { std::cerr << "ERROR: no valid options in chapter " << character.GetCurrentChapter() << std::endl << "Options:\n" ; assert(GetOptions().GetOptions().size() == 2); } while (1) { if (m_verbose) { std::clog << "Let the use choose a valid option" << std::endl; } auto options = GetOptions().GetValidOptions(character); //If there are options, add (1) showing inventory (2) eating provision (3) drinking potion if (options.size() > 1) { //Add to show the inventory options.push_back(CreateShowInventoryOption()); if (character.GetProvisions() > 0) { options.push_back(CreateEatProvisionOption()); } if (character.HasPotion()) { options.push_back(CreateDrinkPotionOption()); } } if (m_verbose) { std::clog << "Do the request" << std::endl; } assert(m_observer); const auto chosen = m_observer->RequestOption(options); if (m_verbose) { std::clog << "Done the request" << std::endl; } ShowText("\n"); if (chosen.GetConsequence().GetType() == ConsequenceType::show_inventory) { //Showing the inventory is trivial this->ShowText(character.ShowInventory()); continue; } if (chosen.GetConsequence().GetType() == ConsequenceType::eat_provision) { character.ChangeProvisions(-1); character.ChangeCondition(4); continue; } if (chosen.GetConsequence().GetType() == ConsequenceType::drink_potion) { character.DrinkPotion(); continue; } chosen.DoChoose(character); assert(m_consequence.GetNextChapter() == -1); //Only apply these consequences once m_consequence.Apply(character); break; } } else if (GetType() == ChapterType::fight) { const int n_chapters_before{static_cast<int>(character.GetChapters().size())}; m_fighting_chapter.Do(character); if (character.IsDead()) { m_game_lost_chapter.Do(character); return; } assert(m_consequence.GetNextChapter() > 0); const int n_chapters_after{static_cast<int>(character.GetChapters().size())}; if (n_chapters_after != n_chapters_before) { //Player has escaped //Check that there are no other consequences that need to be applied assert(m_consequence.GetChangeArrows() == 0); assert(m_consequence.GetChangeCondition() == 0); assert(m_consequence.GetChangeGold() == 0); assert(m_consequence.GetChangeLuck() == 0); assert(m_consequence.GetChangeProvisions() == 0); assert(m_consequence.GetChangeSkill() == 0); assert(m_consequence.GetItemsToAdd().empty()); assert(m_consequence.GetItemsToRemove().empty()); } else { m_consequence.Apply(character); } } else if (GetType() == ChapterType::test_your_luck) { GetLuck().Do(character); } else if (GetType() == ChapterType::test_your_skill) { GetSkill().Do(character); } else if (GetType() == ChapterType::shop) { GetShop().Do(character); m_consequence.Apply(character); } else if (GetType() == ChapterType::pawn_shop) { GetPawnShop().Do(character); m_consequence.Apply(character); } else if (GetType() == ChapterType::normal) { //Nothing m_consequence.Apply(character); } else { assert(!"Should not get here"); } if (character.IsDead()) { m_game_lost_chapter.Do(character); return; } ShowText(m_bye_text); }