Skill Set Bonus Sistemi

lmaohw

Bir kalp bir kere sever.
Gold Üye
Geliştirici
Yardımsever Üye
Usta Üye
Mesaj
686
Çözümler
37
Beğeni
735
Puan
919
Ticaret Puanı
0
Selamlar forumda Skill Set Bonusu ile ilgili bir konu göremedim sadece forumdada değil internette bulamadım bu yüzden forumdaki üyelerimizin yararlanabilmesi adına buraya açıp paylaşmayı düşündüm. Tabi bu şuanda p üzeri set bonus sistemi p için değil. Sage ve Legendary içindir.


Burayı görüntülemek için üye girişi yapmalı veya kayıt olmalısınız.
 
En son bir moderatör tarafından düzenlenmiş:
Elinize sağlık hocam skill tooltip inde mi yazdırıyor bu sistemi kullanan 55 120ler verdiği özellikleri bir ufak da pyde bilgi satırı ekledik mi tamamdır
 
Elinize sağlık hocam skill tooltip inde mi yazdırıyor bu sistemi kullanan 55 120ler verdiği özellikleri bir ufak da pyde bilgi satırı ekledik mi tamamdır
Hocam ben skillde göstermek yerine sol üste premium affect olarak ekledim bunu yapmak istersenizde ;

root içerisinde uiaffectshower.py açın ;
//bul
Python:
Genişlet Daralt Kopyala
            MALL_DESC_IDX_START+player.POINT_PC_BANG_DROP_BONUS: (localeInfo.TOOLTIP_MALL_ITEMBONUS_P_STATIC, "d:/ymir work/ui/skill/common/affect/Item_Bonus_p_on.sub",),

//altına ekle

Python:
Genişlet Daralt Kopyala
            777 : (localeInfo.TOOLTIP_SAGE_SET_BONUS, "d:/ymir work/ui/skill/common/affect/marriage_fast.sub",),

locale içerisine gir ve locale_game.txt dosyasına ekle ;

Kod:
Genişlet Daralt Kopyala
TOOLTIP_SAGE_SET_BONUS    Sage Set Bonus\n\nCanavarlara karşı güçlü +%4000\nMetin taşlarına karşı güçlü +%4000\nPatronlara karşı güçlü +%4000\nGüç / +%500\nOrtalama Zarar %20    SNA
 
Selamlar forumda Skill Set Bonusu ile ilgili bir konu göremedim sadece forumdada değil internette bulamadım bu yüzden forumdaki üyelerimizin yararlanabilmesi adına buraya açıp paylaşmayı düşündüm. Tabi bu şuanda p üzeri set bonus sistemi p için değil. Sage ve Legendary içindir.


Alıntılarda özel içerikler gözükmez.
Allah razı olsun, bugün tam da bunu arıyordum. Ben de istek olarak açmayı düşünüyordum ama sen konuyu açmışsın. Teşekkürler.
 
aynen nasıl yapabliriz
Cpp:
Genişlet Daralt Kopyala
#ifdef ENABLE_SKILL_SET_BONUS

constexpr BYTE SKILL_COUNT = 6;
static const DWORD SkillList[JOB_MAX_NUM][SKILL_GROUP_MAX_NUM][SKILL_COUNT] =
{
    { {    1,    2,    3,    4,    5,    6    }, {    16,    17,    18,    19,    20,    21    } }, // savasci bedensel - zihinsel
    { {    31,    32,    33,    34,    35,    36    }, {    46,    47,    48,    49,    50,    51    } }, // ninja yakin - uzak
    { {    61,    62,    63,    64,    65,    66    }, {    76,    77,    78,    79,    80,    81    } }, // sura buyulu - kara buyu
    { {    91,    92,    93,    94,    95,    96    }, {    106,107,108,109,110,111    } }, // saman ejderha - iyilestirme
#ifdef ENABLE_WOLFMAN_CHARACTER
    { {    170,171,172,173,174,175    }, {    0,    0,    0,    0,    0,    0    } }, // kurt
#endif
};

enum class ESkillSetState {
    TYPE_FAIL,
    TYPE_LEGENDARY,
};

static const uint32_t skillSetBonusTable[1][4][2] =
{
    {// legendary bonuslar
        {  POINT_ATTBONUS_MONSTER, 3000 },
        {  POINT_ATTBONUS_STONE, 3000 },
        {  POINT_ATTBONUS_BOSS, 3000 },
        {  POINT_ST, 500 },
    }
};

constexpr uint8_t SAGE_LEVEL = 50; // sage_level skill leveli (default 50)
constexpr uint8_t LEGENDARY_LEVEL = 60; // legendary skill leveli (default 60)

void CHARACTER::CheckSkillBonus() {
    const auto& tempList = SkillList[GetJob()][GetSkillGroup() - 1];
    const auto& giveAffects = [&](const auto& arr, const auto aff) { // -> affect lambd
        if (FindAffect(aff)) { return; }
        const auto arrSize = sizeof(arr) / sizeof(arr[0]);
        for (unsigned i(0); i < arrSize; ++i) {
            const auto bonus = arr[i][0];
            const auto val = arr[i][1];
            if (val == 0) { continue; }
            AddAffect(aff, bonus, val, 0, INFINITE_AFFECT_DURATION, 0, true, true);
            if (IsGM()) { ChatPacket(1, "[GM_INFO] SkillSetBonus adding point : %u, val : %u", bonus, val); }
        }
    };

    auto state = ESkillSetState::TYPE_LEGENDARY;

    // sage begin
    for (const auto skillVnum : tempList)
    {
        //if (skillVnum == 0) { continue; }
        if (GetSkillLevel(skillVnum) < LEGENDARY_LEVEL) {
            state = ESkillSetState::TYPE_FAIL;
            break;
        }
    }

    if (state == ESkillSetState::TYPE_FAIL) {
        if (FindAffect(AFFECT_SAGE_SKILL_SET_BONUS)) { RemoveAffect(AFFECT_SAGE_SKILL_SET_BONUS); return; }
    }
    else {
        auto& setBonusList = skillSetBonusTable[static_cast<BYTE>(ESkillSetState::TYPE_LEGENDARY) - 1];
        giveAffects(setBonusList, AFFECT_SAGE_SKILL_SET_BONUS);
    }

    // sage end
/*
    // legendary begin
    state = ESkillSetState::TYPE_LEGENDARY;
    for (const auto skillVnum : tempList)
    { // check sage
        if (skillVnum == 0) { continue; }
        if (GetSkillLevel(skillVnum) < LEGENDARY_LEVEL) {
            state = ESkillSetState::TYPE_FAIL;
            break;
        }
    }

    if (state == ESkillSetState::TYPE_FAIL) {
        if (FindAffect(AFFECT_LEG_SKILL_SET_BONUS)) { RemoveAffect(AFFECT_LEG_SKILL_SET_BONUS); }
    }
    else {
        auto& setBonusList = skillSetBonusTable[static_cast<BYTE>(ESkillSetState::TYPE_LEGENDARY) - 1];
        giveAffects(setBonusList, AFFECT_LEG_SKILL_SET_BONUS);
    }
    // legendary end
*/
}
#endif


Buradaki skill vunumlarını p skilin olması gerekiyor deneyip bakabilirsin hata alırsan buradan yardımcı oluruz
 
Yıllar önce ben yazmıştım bunu, sanırım şu an olsa şuna benzer bir şey yazardım(hatam varsa affola, isimlendirmeyede çok takılmayın üstüne pek düşmedim);

Not: Min. C++20. Oyun içinde denemedim, kullanmak isteyen olursa deneyip varsa sorun bildirebilir.
Not2: Bonus mantığı dinamikleştirilebilir, şu an genişlemeye tam olarak açık denemez, ben üşendim o da size kalsın :)


C++:
Genişlet Daralt Kopyala
#include <algorithm>
#include <array>
#include <cstdint>
#include <iostream>
#include <optional>
#include <ranges>
#include <span>
#include <type_traits>

// already C++23
namespace compat {
template<typename E>
    requires std::is_enum_v<E>
constexpr auto to_underlying(E e) noexcept
{
    return static_cast<std::underlying_type_t<E>>(e);
}
}  // namespace compat

using skill_id_t = std::uint8_t;
using skill_level_t = std::uint8_t;

static constexpr std::size_t MAX_SKILL_NUM{255};

struct TPlayerSkill
{
    std::uint8_t bMasterType{};
    skill_level_t bLevel{};
};

using player_skill_span_t = std::span<const TPlayerSkill>;

namespace skill_system {

static constexpr skill_level_t level_threshold_perfect{30};
static constexpr skill_level_t level_threshold_legendary{40};

static constexpr std::size_t skill_group_size{6};
static constexpr std::size_t skill_group_max{2};

enum class JobType : std::uint8_t {
    WARRIOR = 0U,
    ASSASSIN,
    SURA,
    SHAMAN,
#ifdef ENABLE_WOLFMAN_CHARACTER
    WOLFMAN,
#endif
    MAX_NUM
};

static constexpr auto job_count{compat::to_underlying(JobType::MAX_NUM)};

struct SkillGroup
{
    std::array<skill_id_t, skill_group_size> ids{};

    [[nodiscard]] constexpr auto active_skills() const noexcept
    {
        return ids | std::views::filter([](skill_id_t id) {
                   return 0 != id;
               });
    }
};

using job_skill_table_t = std::array<std::array<SkillGroup, skill_group_max>, job_count>;

template<std::integral... Args>
consteval SkillGroup make_group(Args... args) noexcept
{
    static_assert(sizeof...(Args) == skill_group_size, "Skill group size mismatch");
    return SkillGroup{.ids = {static_cast<skill_id_t>(args)...}};
}

static constexpr job_skill_table_t job_skill_table{{
    {{// WARRIOR
      make_group(1, 2, 3, 4, 5, 6),
      make_group(16, 17, 18, 19, 20, 21)
    }},
    {{// ASSASSIN
      make_group(31, 32, 33, 34, 35, 36),
      make_group(46, 47, 48, 49, 50, 51)
    }},
    {{// SURA
      make_group(61, 62, 63, 64, 65, 66),
      make_group(76, 77, 78, 79, 80, 81)
    }},
    {{// SHAMAN
      make_group(91, 92, 93, 94, 95, 96),
      make_group(106, 107, 108, 109, 110, 111)
    }},
#ifdef ENABLE_WOLFMAN_CHARACTER
    {{// WOLFMAN
      make_group(170, 171, 172, 173, 174, 175),
      make_group(0, 0, 0, 0, 0, 0)
    }},
#endif
}};

static_assert(job_skill_table.size() == job_count, "Job skill table size mismatch!");

[[nodiscard]] bool is_group_valid(
    JobType job, std::uint8_t group_idx, skill_level_t min_level, player_skill_span_t player_skills
) noexcept
{
    const auto job_idx{compat::to_underlying(job)};

    if (job_skill_table.size() <= job_idx or skill_group_max <= group_idx)
    {
        return false;
    }

    auto group_skills{job_skill_table[job_idx][group_idx].active_skills()};

    return std::ranges::all_of(group_skills, [&player_skills, min_level](skill_id_t id) {
        if (player_skills.size() <= id)
        {
            return false;
        }

        return player_skills[id].bLevel >= min_level;
    });
}

enum class BonusType : std::uint8_t {
    PERFECT,
    LEGENDARY,
    MAX
};

struct BonusPoint
{
    std::uint8_t type;
    std::uint16_t value;
};

struct BonusData
{
    static constexpr std::size_t bonus_max_num{5ULL};
    std::array<BonusPoint, bonus_max_num> points{};
};

// template <BonusType type>
consteval BonusData get_bonus_config(BonusType type) noexcept
{
    using enum BonusType;
    // all values mock

    if (PERFECT == type)
    {
        return {.points = {{{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5, 50}}}};
    }

    if (LEGENDARY == type)
    {
        return {.points = {{{1, 100}, {2, 200}, {3, 300}, {4, 400}, {5, 500}}}};
    }

    return {};
}

static constexpr auto bonus_config_table{
    std::to_array({get_bonus_config(BonusType::PERFECT), get_bonus_config(BonusType::LEGENDARY)})
};

void apply_bonus_effect(BonusType type, bool is_adding)
{
    const auto idx{compat::to_underlying(type)};

    if (bonus_config_table.size() <= idx)
    {
        return;
    }

    const auto& bonus_data{bonus_config_table[idx]};
    const auto type_str{(type == BonusType::PERFECT) ? "PERFECT" : "LEGENDARY"};
    const auto action_str{is_adding ? "[APPLY]" : "[REMOVE]"};

    std::cout << ">> " << action_str << " Bonus Type: " << type_str << "\n";

    auto valid_points{bonus_data.points | std::views::filter([](const auto& elm) {
                          static constexpr std::uint16_t zero_value{0U};
                          return zero_value != elm.value;
                      })};

    for (const auto& [pt_type, value]: valid_points)
    {
        const char sign{is_adding ? '+' : '-'};
        std::cout << "   -> Point: " << static_cast<int>(pt_type) << " Value: " << sign << value << "\n";
    }
}

[[nodiscard]] std::optional<BonusType> calculate_state_bonus(
    JobType job, std::uint8_t group, player_skill_span_t skills
)
{
    using enum BonusType;

    if (is_group_valid(job, group, level_threshold_legendary, skills))
    {
        return LEGENDARY;
    }

    if (is_group_valid(job, group, level_threshold_perfect, skills))
    {
        return PERFECT;
    }

    return std::nullopt;
}

void update_bonus_state(
    JobType job, std::uint8_t group, player_skill_span_t skills, std::optional<BonusType>& current_state
)
{
    const auto new_state{calculate_state_bonus(job, group, skills)};

    if (new_state == current_state)
    {
        std::cout << "\n[NO CHANGE] Status is stable.\n";
        return;
    }

    std::cout << "\n[STATUS CHANGE DETECTED]\n";

    if (current_state.has_value())
    {
        apply_bonus_effect(current_state.value(), false);
    }

    if (new_state.has_value())
    {
        apply_bonus_effect(new_state.value(), true);
    }

    current_state = new_state;
}
}  // namespace skill_system

// mock datas
static std::array<TPlayerSkill, MAX_SKILL_NUM> g_player_skills{};
static std::optional<skill_system::BonusType> g_current_bonus_state{std::nullopt};

int main()
{
    using namespace skill_system;

    std::cout << "--- SYSTEM START ---\n";

    constexpr auto my_job{JobType::WARRIOR};
    constexpr std::uint8_t my_group{0U};

    const auto set_all_skills{[](skill_level_t level) {
        for (int i{1}; i <= 6; ++i)
        {
            g_player_skills[i].bLevel = level;
        }
    }};

    std::cout << "\n--- Scenario 1: Low Skills (All 20) ---";
    set_all_skills(20);
    update_bonus_state(my_job, my_group, g_player_skills, g_current_bonus_state);

    std::cout << "\n--- Scenario 2: Skills Upgraded to Perfect (All 35) ---";
    set_all_skills(35);
    update_bonus_state(my_job, my_group, g_player_skills, g_current_bonus_state);

    std::cout << "\n--- Scenario 3: Skills Upgraded to Legendary (All 45) ---";
    set_all_skills(45);
    update_bonus_state(my_job, my_group, g_player_skills, g_current_bonus_state);

    std::cout << "\n--- Scenario 4: One Skill Downgraded (Skill[6] = 25) ---";
    g_player_skills[6].bLevel = 25;
    update_bonus_state(my_job, my_group, g_player_skills, g_current_bonus_state);

    std::cout << "\n--- Scenario 5: Skills Restored to Perfect (All 30) ---";
    set_all_skills(30);
    update_bonus_state(my_job, my_group, g_player_skills, g_current_bonus_state);

    return EXIT_SUCCESS;
}

live demo:
 
Geri
Üst