bool SkillManager::awardSkill(const String& skillName, CreatureObject* creature, bool notifyClient, bool awardRequiredSkills, bool noXpRequired) { Skill* skill = skillMap.get(skillName.hashCode()); if (skill == NULL) return false; Locker locker(creature); //Check for required skills. Vector<String>* requiredSkills = skill->getSkillsRequired(); for (int i = 0; i < requiredSkills->size(); ++i) { String requiredSkillName = requiredSkills->get(i); Skill* requiredSkill = skillMap.get(requiredSkillName.hashCode()); if (requiredSkill == NULL) continue; if (awardRequiredSkills) awardSkill(requiredSkillName, creature, notifyClient, awardRequiredSkills, noXpRequired); if (!creature->hasSkill(requiredSkillName)) return false; } if (!canLearnSkill(skillName, creature, noXpRequired)) { return false; } //If they already have the skill, then return true. if (creature->hasSkill(skill->getSkillName())) return true; ManagedReference<PlayerObject*> ghost = creature->getPlayerObject(); if (ghost != NULL) { //Withdraw skill points. ghost->addSkillPoints(-skill->getSkillPointsRequired()); //Witdraw experience. if (!noXpRequired) { ghost->addExperience(skill->getXpType(), -skill->getXpCost(), true); } creature->addSkill(skill, notifyClient); //Add skill modifiers VectorMap<String, int>* skillModifiers = skill->getSkillModifiers(); for (int i = 0; i < skillModifiers->size(); ++i) { VectorMapEntry<String, int>* entry = &skillModifiers->elementAt(i); creature->addSkillMod(SkillModManager::SKILLBOX, entry->getKey(), entry->getValue(), notifyClient); } //Add abilities Vector<String>* abilityNames = skill->getAbilities(); addAbilities(ghost, *abilityNames, notifyClient); if (skill->isGodOnly()) { for (int i = 0; i < abilityNames->size(); ++i) { String ability = abilityNames->get(i); StringIdChatParameter params; params.setTU(ability); params.setStringId("ui", "skill_command_acquired_prose"); creature->sendSystemMessage(params); } } //Add draft schematic groups Vector<String>* schematicsGranted = skill->getSchematicsGranted(); SchematicMap::instance()->addSchematics(ghost, *schematicsGranted, notifyClient); //Update maximum experience. updateXpLimits(ghost); // Update Force Power Max. ghost->setForcePowerMax(creature->getSkillMod("jedi_force_power_max"), true); if (skillName.contains("master")) { ManagedReference<PlayerManager*> playerManager = creature->getZoneServer()->getPlayerManager(); if (playerManager != NULL) { const Badge* badge = BadgeList::instance()->get(skillName); if (badge == NULL && skillName == "crafting_shipwright_master") { badge = BadgeList::instance()->get("crafting_shipwright"); } if (badge != NULL) { playerManager->awardBadge(ghost, badge); } } } SkillList* list = creature->getSkillList(); int totalSkillPointsWasted = 250; for (int i = 0; i < list->size(); ++i) { Skill* skill = list->get(i); totalSkillPointsWasted -= skill->getSkillPointsRequired(); } if (ghost->getSkillPoints() != totalSkillPointsWasted) { creature->error("skill points mismatch calculated: " + String::valueOf(totalSkillPointsWasted) + " found: " + String::valueOf(ghost->getSkillPoints())); ghost->setSkillPoints(totalSkillPointsWasted); } ManagedReference<PlayerManager*> playerManager = creature->getZoneServer()->getPlayerManager(); if (playerManager != NULL) { creature->setLevel(playerManager->calculatePlayerLevel(creature)); } } /// Update client with new values for things like Terrain Negotiation CreatureObjectDeltaMessage4* msg4 = new CreatureObjectDeltaMessage4(creature); msg4->updateAccelerationMultiplierBase(); msg4->updateAccelerationMultiplierMod(); msg4->updateSpeedMultiplierBase(); msg4->updateSpeedMultiplierMod(); msg4->updateRunSpeed(); msg4->updateTerrainNegotiation(); msg4->close(); creature->sendMessage(msg4); SkillModManager::instance()->verifySkillBoxSkillMods(creature); return true; }
std::vector<SecondarySkill> CGHeroInstance::getLevelUpProposedSecondarySkills() const { std::vector<SecondarySkill> obligatorySkills; //hero is offered magic school or wisdom if possible if (!skillsInfo.wisdomCounter) { if (cb->isAllowed(2, SecondarySkill::WISDOM) && !getSecSkillLevel(SecondarySkill::WISDOM)) obligatorySkills.push_back(SecondarySkill::WISDOM); } if (!skillsInfo.magicSchoolCounter) { std::vector<SecondarySkill> ss = { SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC }; std::shuffle(ss.begin(), ss.end(), skillsInfo.rand.getStdGenerator()); for (auto skill : ss) { if (cb->isAllowed(2, skill) && !getSecSkillLevel(skill)) //only schools hero doesn't know yet { obligatorySkills.push_back(skill); break; //only one } } } std::vector<SecondarySkill> skills; //picking sec. skills for choice std::set<SecondarySkill> basicAndAdv, expert, none; for(int i=0;i<GameConstants::SKILL_QUANTITY;i++) if (cb->isAllowed(2,i)) none.insert(SecondarySkill(i)); for(auto & elem : secSkills) { if(elem.second < SecSkillLevel::EXPERT) basicAndAdv.insert(elem.first); else expert.insert(elem.first); none.erase(elem.first); } for (auto s : obligatorySkills) //don't duplicate them { none.erase (s); basicAndAdv.erase (s); expert.erase (s); } //first offered skill: // 1) give obligatory skill // 2) give any other new skill // 3) upgrade existing if (canLearnSkill() && obligatorySkills.size() > 0) { skills.push_back (obligatorySkills[0]); } else if(none.size() && canLearnSkill()) //hero have free skill slot { skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.rand)); //new skill none.erase(skills.back()); } else if(!basicAndAdv.empty()) { skills.push_back(type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.rand)); //upgrade existing basicAndAdv.erase(skills.back()); } //second offered skill: //1) upgrade existing //2) give obligatory skill //3) give any other new skill if(!basicAndAdv.empty()) { SecondarySkill s = type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.rand);//upgrade existing skills.push_back(s); basicAndAdv.erase(s); } else if (canLearnSkill() && obligatorySkills.size() > 1) { skills.push_back (obligatorySkills[1]); } else if(none.size() && canLearnSkill()) { skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.rand)); //give new skill none.erase(skills.back()); } if (skills.size() == 2) // Fix for #1868 to avoid changing logic (possibly causing bugs in process) std::swap(skills[0], skills[1]); return skills; }