/* EQ2Emulator: Everquest II Server Emulator Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) This file is part of EQ2Emulator. EQ2Emulator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. EQ2Emulator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with EQ2Emulator. If not, see . */ #include "Skills.h" #include "Spawn.h" #include "../common/Log.h" extern ConfigReader configReader; MasterSkillList::MasterSkillList(){ } MasterSkillList::~MasterSkillList(){ map::iterator itr; for(itr = skills.begin(); itr != skills.end(); itr++){ safe_delete(itr->second); } map::iterator itr2; for(itr2 = populate_packets.begin(); itr2 != populate_packets.end(); itr2++){ safe_delete(itr2->second); } } Skill::Skill(){ skill_id = 0; current_val = 0; previous_val = 0; max_val = 0; skill_type = 0; display = 0; save_needed = false; } Skill::Skill(Skill* skill){ skill_id = skill->skill_id; current_val = skill->current_val; previous_val = skill->current_val; max_val = skill->max_val; skill_type = skill->skill_type; display = skill->display; short_name = skill->short_name; name = skill->name; description = skill->description; save_needed = false; } map* MasterSkillList::GetAllSkills(){ return &skills; } Skill* MasterSkillList::GetSkill(int32 skill_id){ if(skills.count(skill_id) > 0) return skills[skill_id]; else return 0; } Skill* MasterSkillList::GetSkillByName(const char* skill_name) { Skill* skill = 0; map::iterator itr; for (itr = skills.begin(); itr != skills.end(); itr++) { Skill* current_skill = itr->second; if (::ToLower(string(current_skill->name.data.c_str())) == ::ToLower(string(skill_name))) { skill = current_skill; break; } } return skill; } int16 MasterSkillList::GetSkillCount(){ return skills.size(); } void MasterSkillList::AddSkill(Skill* skill){ if(skill) skills[skill->skill_id] = skill; } EQ2Packet* MasterSkillList::GetPopulateSkillsPacket(int16 version){ EQ2Packet* ret = 0; int16 packet_version = configReader.GetStructVersion("WS_SkillMap", version); if(populate_packets.count(packet_version) > 0) ret = populate_packets[packet_version]; else{ PacketStruct* packet = configReader.getStruct("WS_SkillMap", packet_version); int32 count = skills.size(); Skill* skill = 0; int32 i = 0; packet->setArrayLengthByName("skill_count", count); map::iterator itr; for(itr = skills.begin(); itr != skills.end(); itr++, i++){ skill = itr->second; packet->setArrayDataByName("skill_id", skill->skill_id, i); packet->setArrayDataByName("short_name", &skill->short_name, i); packet->setArrayDataByName("name", &skill->name, i); packet->setArrayDataByName("description", &skill->description, i); } populate_packets[packet_version] = packet->serialize(); safe_delete(packet); ret = populate_packets[packet_version]; } if(ret) return ret->Copy(); //need to return a copy as the packet is deleted after the client confirms it and we want to keep the packet to prevent constant generation of the same data else return ret; } PlayerSkillList::PlayerSkillList(){ xor_packet = 0; orig_packet = 0; packet_count = 0; has_updates = false; MSkillUpdates.SetName("PlayerSkillList::MSkillUpdates"); } PlayerSkillList::~PlayerSkillList(){ map::iterator itr; for(itr = skills.begin(); itr != skills.end(); itr++){ safe_delete(itr->second); } MutexMap::iterator sb_itr = skill_bonus_list.begin(); while (sb_itr.Next()) RemoveSkillBonus(sb_itr.first); safe_delete_array(xor_packet); safe_delete_array(orig_packet); } void PlayerSkillList::AddSkill(Skill* new_skill){ skills[new_skill->skill_id] = new_skill; } void PlayerSkillList::RemoveSkill(Skill* skill) { if (skill) skills.erase(skill->skill_id); } map* PlayerSkillList::GetAllSkills(){ return &skills; } void PlayerSkillList::SetSkillValuesByType(int8 type, int16 value, bool send_update) { map::iterator itr; for (itr = skills.begin(); itr != skills.end(); itr++) { if (itr->second && itr->second->skill_type == type) SetSkill(itr->second, value, send_update); } } void PlayerSkillList::SetSkillCapsByType(int8 type, int16 value){ map::iterator itr; for(itr = skills.begin(); itr != skills.end(); itr++){ if(itr->second && itr->second->skill_type == type) SetSkillCap(itr->second, value); } } void PlayerSkillList::IncreaseSkillCapsByType(int8 type, int16 value){ map::iterator itr; for(itr = skills.begin(); itr != skills.end(); itr++){ if(itr->second && itr->second->skill_type == type) IncreaseSkillCap(itr->second, value); } } void PlayerSkillList::IncreaseAllSkillCaps(int16 value){ map::iterator itr; for(itr = skills.begin(); itr != skills.end(); itr++){ IncreaseSkillCap(itr->second, value); } } bool PlayerSkillList::HasSkill(int32 skill_id){ return (skills.count(skill_id) > 0); } Skill* PlayerSkillList::GetSkill(int32 skill_id){ if(skills.count(skill_id) > 0) return skills[skill_id]; else return 0; } void PlayerSkillList::IncreaseSkill(Skill* skill, int16 amount){ if(skill){ skill->previous_val = skill->current_val; skill->current_val += amount; if(skill->current_val > skill->max_val) skill->max_val = skill->current_val; AddSkillUpdateNeeded(skill); skill->save_needed = true; } } void PlayerSkillList::IncreaseSkill(int32 skill_id, int16 amount){ IncreaseSkill(GetSkill(skill_id), amount); } void PlayerSkillList::DecreaseSkill(Skill* skill, int16 amount){ if(skill){ skill->previous_val = skill->current_val; if((skill->current_val - amount) < 0) skill->current_val = 0; else skill->current_val -= amount; skill->save_needed = true; AddSkillUpdateNeeded(skill); } } void PlayerSkillList::DecreaseSkill(int32 skill_id, int16 amount){ DecreaseSkill(GetSkill(skill_id), amount); } void PlayerSkillList::SetSkill(Skill* skill, int16 value, bool send_update){ if(skill){ skill->previous_val = skill->current_val; skill->current_val = value; if(skill->current_val > skill->max_val) skill->max_val = skill->current_val; skill->save_needed = true; if(send_update) AddSkillUpdateNeeded(skill); } } void PlayerSkillList::SetSkill(int32 skill_id, int16 value, bool send_update){ SetSkill(GetSkill(skill_id), value, send_update); } void PlayerSkillList::IncreaseSkillCap(Skill* skill, int16 amount){ if(skill){ skill->max_val += amount; skill->save_needed = true; } } void PlayerSkillList::IncreaseSkillCap(int32 skill_id, int16 amount){ IncreaseSkillCap(GetSkill(skill_id), amount); } void PlayerSkillList::DecreaseSkillCap(Skill* skill, int16 amount){ if(skill){ if((skill->max_val - amount) < 0) skill->max_val = 0; else skill->max_val -= amount; if(skill->current_val > skill->max_val){ skill->previous_val = skill->current_val; skill->current_val = skill->max_val; } AddSkillUpdateNeeded(skill); skill->save_needed = true; } } void PlayerSkillList::DecreaseSkillCap(int32 skill_id, int16 amount){ DecreaseSkillCap(GetSkill(skill_id), amount); } void PlayerSkillList::SetSkillCap(Skill* skill, int16 value){ if(skill){ skill->max_val = value; if(skill->current_val > skill->max_val){ skill->previous_val = skill->current_val; skill->current_val = skill->max_val; } AddSkillUpdateNeeded(skill); skill->save_needed = true; } } void PlayerSkillList::SetSkillCap(int32 skill_id, int16 value){ SetSkillCap(GetSkill(skill_id), value); } int16 PlayerSkillList::CalculateSkillValue(int32 skill_id, int16 current_val){ if (current_val > 5) { int16 new_val = current_val; MutexMap::iterator itr = skill_bonus_list.begin(); while (itr.Next()) { SkillBonus* sb = itr.second; map::iterator sbv_itr; for (sbv_itr = sb->skills.begin(); sbv_itr != sb->skills.end(); sbv_itr++) { SkillBonusValue* sbv = sbv_itr->second; if (sbv->skill_id == skill_id) new_val += (int16)sbv->value; } } return new_val; } return current_val; } int16 PlayerSkillList::CalculateSkillMaxValue(int32 skill_id, int16 max_val) { int16 new_val = max_val; MutexMap::iterator itr = skill_bonus_list.begin(); while (itr.Next()) { SkillBonus* sb = itr->second; map::iterator sbv_itr; for (sbv_itr = sb->skills.begin(); sbv_itr != sb->skills.end(); sbv_itr++) { SkillBonusValue* sbv = sbv_itr->second; if (sbv->skill_id == skill_id) new_val += (int16)sbv->value; } } return new_val; } EQ2Packet* PlayerSkillList::GetSkillPacket(int16 version){ PacketStruct* packet = configReader.getStruct("WS_UpdateSkillBook", version); if(packet){ if(packet_count < skills.size()){ int16 size = 0; if (version > 546) { size = 21 * skills.size() + 8; } else if (version <= 283) { size = 12 * skills.size() + 6; } else if (version <= 546) { size = 21 * skills.size() + 7; } if(!orig_packet){ xor_packet = new uchar[size]; orig_packet = new uchar[size]; memset(xor_packet, 0, size); memset(orig_packet, 0, size); orig_packet_size = size; } else{ uchar* tmp = new uchar[size]; memset(tmp, 0, size); memcpy(tmp, orig_packet, orig_packet_size); safe_delete_array(orig_packet); orig_packet = tmp; safe_delete_array(xor_packet); xor_packet = new uchar[size]; } packet_count = skills.size(); } packet->setArrayLengthByName("skill_count", skills.size()); map::iterator itr; Skill* skill = 0; int32 i=0; for(itr = skills.begin(); itr != skills.end(); itr++){ skill = itr->second; if(skill){ int16 skill_max_with_bonuses = CalculateSkillMaxValue(skill->skill_id, skill->max_val); int16 skill_with_bonuses = int(CalculateSkillValue(skill->skill_id, skill->current_val)); if (skill->skill_id == 613995491) { int x_current = skill->current_val; int x_previous = skill->previous_val; int x_max = skill->max_val; int x_delta2 = skill_max_with_bonuses - skill->max_val; int xxx = 1; } packet->setArrayDataByName("skill_id", skill->skill_id, i); if (version <= 546 && skill->skill_type >= SKILL_TYPE_GENERAL) { //covert it to DOF types packet->setArrayDataByName("type", skill->skill_type-2, i); } else packet->setArrayDataByName("type", skill->skill_type, i); packet->setArrayDataByName("current_val", skill->current_val, i); packet->setArrayDataByName("base_val", skill->current_val, i);// skill-> packet->setArrayDataByName("skill_delta", 0, i);// skill_with_bonuses- skill->current_val packet->setArrayDataByName("skill_delta2", skill_max_with_bonuses - skill->max_val, i);// skill_max_with_bonuses - skill->max_val, i); packet->setArrayDataByName("max_val", skill->max_val, i); packet->setArrayDataByName("display_minval", skill->display, i); packet->setArrayDataByName("display_maxval", skill->display, i); i++; } } int8 offset = 1; if (version <= 283) offset = 0; EQ2Packet* ret = packet->serializeCountPacket(version, offset, orig_packet, xor_packet); //packet->PrintPacket(); //DumpPacket(orig_packet, orig_packet_size); //DumpPacket(ret); safe_delete(packet); return ret; } return 0; } bool PlayerSkillList::CheckSkillIncrease(Skill* skill){ if(!skill || skill->current_val >= skill->max_val) return false; // Assuming that skills will be used more at higher levels, increase chances are: // skill val of 1 ~ 20% chance, value of 100 ~ 10%, value of 400 ~ 4% int8 percent = (int8)(((float)((float)100/(float)(50 + skill->current_val)))*10); if(rand()%100 < percent){ // skill increase IncreaseSkill(skill, 1); return true; } else return false; } Skill* PlayerSkillList::GetSkillByName(const char* name){ if(name_skill_map.size() == 0){ map::iterator itr; Skill* skill = 0; for(itr = skills.begin(); itr != skills.end(); itr++){ skill = itr->second; name_skill_map[skill->name.data] = skill; } } if(name_skill_map.count(name) > 0) return name_skill_map[name]; else return 0; } vector* PlayerSkillList::GetSaveNeededSkills(){ vector* ret = new vector; map::iterator itr; for(itr = skills.begin(); itr != skills.end(); itr++){ if(itr->second->save_needed){ ret->push_back(itr->second); itr->second->save_needed = false; } } return ret; } void PlayerSkillList::AddSkillUpdateNeeded(Skill* skill){ MSkillUpdates.writelock(__FUNCTION__, __LINE__); skill_updates.push_back(skill); has_updates = true; MSkillUpdates.releasewritelock(__FUNCTION__, __LINE__); } vector* PlayerSkillList::GetSkillUpdates(){ vector* ret = 0; vector::iterator itr; MSkillUpdates.writelock(__FUNCTION__, __LINE__); if(skill_updates.size() > 0){ ret = new vector(); ret->insert(ret->begin(), skill_updates.begin(), skill_updates.end()); skill_updates.clear(); } has_updates = false; MSkillUpdates.releasewritelock(__FUNCTION__, __LINE__); return ret; } bool PlayerSkillList::HasSkillUpdates(){ return has_updates; } void PlayerSkillList::AddSkillBonus(int32 spell_id, int32 skill_id, float value) { if (value != 0) { SkillBonus* sb; if (skill_bonus_list.count(spell_id) == 0) { sb = new SkillBonus; sb->spell_id = spell_id; skill_bonus_list.Put(spell_id, sb); } else sb = skill_bonus_list.Get(spell_id); if (sb->skills[skill_id] == 0) { SkillBonusValue* sbv = new SkillBonusValue; sbv->skill_id = skill_id; sbv->value = value; sb->skills[skill_id] = sbv; } } } SkillBonus* PlayerSkillList::GetSkillBonus(int32 spell_id) { SkillBonus *ret = 0; if (skill_bonus_list.count(spell_id) > 0) ret = skill_bonus_list.Get(spell_id); return ret; } void PlayerSkillList::RemoveSkillBonus(int32 spell_id) { if (skill_bonus_list.count(spell_id) > 0) { SkillBonus* sb = skill_bonus_list.Get(spell_id); skill_bonus_list.erase(spell_id); map::iterator itr; for (itr = sb->skills.begin(); itr != sb->skills.end(); itr++) safe_delete(itr->second); safe_delete(sb); } } int Skill::CheckDisarmSkill(int16 targetLevel, int8 chest_difficulty) { if (chest_difficulty < 2) // no triggers on this chest type return 1; if (targetLevel < 1) targetLevel = 1; int chest_diff_result = targetLevel * chest_difficulty; float base_difficulty = 15.0f; float fail_threshold = 10.0f; float chance = ((100.0f - base_difficulty) * ((float)current_val / (float)chest_diff_result)); if (chance > (100.0f - base_difficulty)) { chance = 100.0f - base_difficulty; } float d100 = (float)MakeRandomFloat(0, 100); if (d100 <= chance) return 1; else { if (d100 > (chance + fail_threshold)) return -1; } return 0; }