Auto-translated
green belly, regarding perks: the most convenient way (probably) would be to create a table where you enter the perks, the type of reward for the perk, and accordingly, the rewards for different levels of mastery. Then, write a function that checks for the presence of the necessary perks and their mastery level, determines the type of reward that should be given, and issues the reward.
Regarding stats for combat: I think you can determine which race a hero belongs to using HasHeroSkill(heroName, ID of racial stats (like "master of artifacts" for mages, "counterattack" for knights, "avenger" for elves, "necromancy" for necromancers, etc.), and if the hero has a particular stat (and, by default, a hero can only have one), assign it to the appropriate race. The same applies to leadership, but to check the mastery level, you need to use the function GetHeroSkillMastery(heroName, skill ID), which returns a number from 0 to 4 (0 - does not possess the perk at all, 1-3 - beginner/developed/proficient, 4 - perfect (like only for racial perks, such as "Perfect Counterattack"). I remind you that perfect levels of racial perks are obtained only through the "Pendant of Mastery" artifact), and according to the mastery level, apply GiveHeroBattleBonus(heroName, HERO_BATTLE_BONUS_MORALE, -the required number).
P.S. The battle bonus function only works in version 3.1