diff --git a/Entity/Character/Character.cs b/Entity/Character/Character.cs
index 0399065..565c662 100644
--- a/Entity/Character/Character.cs
+++ b/Entity/Character/Character.cs
@@ -125,7 +125,12 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
- return Math.Max(1, field + ExLevel);
+ int level = field + ExLevel;
+ if (MaxLevel > 0)
+ {
+ level = Math.Min(level, MaxLevel);
+ }
+ return Math.Max(0, level);
}
set
{
@@ -145,6 +150,11 @@ namespace Milimoe.FunGame.Core.Entity
///
public int ExLevel { get; set; } = 0;
+ ///
+ /// 自定义最大等级
+ ///
+ public int MaxLevel { get; set; } = 0;
+
///
/// 经验值
///
@@ -909,6 +919,11 @@ namespace Milimoe.FunGame.Core.Entity
///
public Character? Master { get; set; } = null;
+ ///
+ /// 角色职业对象
+ ///
+ public CharacterClass Class { get; set; }
+
///
/// 普通攻击对象
///
@@ -941,6 +956,7 @@ namespace Milimoe.FunGame.Core.Entity
MDF = new();
Shield = new();
NormalAttack = new(this);
+ Class = new(this);
}
internal static Character GetInstance()
@@ -1289,6 +1305,7 @@ namespace Milimoe.FunGame.Core.Entity
}
if (isUp)
{
+ Class.OnLevelUp();
Effect[] effects = [.. Effects.Where(e => e.IsInEffect).OrderByDescending(e => e.Priority)];
foreach (Effect e in effects)
{
@@ -2010,6 +2027,7 @@ namespace Milimoe.FunGame.Core.Entity
PrimaryAttribute = PrimaryAttribute,
Level = Level,
ExLevel = ExLevel,
+ MaxLevel = MaxLevel,
LevelBreak = LevelBreak,
EXP = EXP,
InitialHP = InitialHP,
@@ -2124,6 +2142,7 @@ namespace Milimoe.FunGame.Core.Entity
PrimaryAttribute = c.PrimaryAttribute;
Level = c.Level;
ExLevel = c.ExLevel;
+ MaxLevel = c.MaxLevel;
LevelBreak = c.LevelBreak;
EXP = c.EXP;
CharacterState = c.CharacterState;
diff --git a/Entity/Character/CharacterClass.cs b/Entity/Character/CharacterClass.cs
new file mode 100644
index 0000000..f45760f
--- /dev/null
+++ b/Entity/Character/CharacterClass.cs
@@ -0,0 +1,141 @@
+using Milimoe.FunGame.Core.Library.Constant;
+
+namespace Milimoe.FunGame.Core.Entity
+{
+ ///
+ /// 角色职业管理类
+ ///
+ ///
+ public class CharacterClass(Character character)
+ {
+ ///
+ /// 所属的角色
+ ///
+ public Character Character { get; set; } = character;
+
+ ///
+ /// 职业点数
+ ///
+ public int ClassPoints { get; set; } = 1;
+
+ ///
+ /// 已选择职业
+ ///
+ public HashSet Classes { get; set; } = [];
+
+ ///
+ /// 已选择流派
+ ///
+ public HashSet SubClasses { get; set; } = [];
+
+ ///
+ /// 已激活战斗天赋
+ ///
+ public Skill? CombatTalent { get; set; } = null;
+
+ ///
+ /// 通过升级重新计算职业点数
+ ///
+ public void OnLevelUp()
+ {
+ ClassPoints = 0;
+ foreach (int level in Character.GameplayEquilibriumConstant.ClassPointsGetterList)
+ {
+ if (Character.Level >= level)
+ {
+ ClassPoints++;
+ }
+ }
+ if (ClassPoints == 0)
+ {
+ ClassPoints = 1;
+ }
+ }
+
+ ///
+ /// 重新构建角色职业,设置定位和技能等
+ ///
+ ///
+ public void ReBuildCharacterClass(ClassObject obj)
+ {
+ Character.FirstRoleType = RoleType.None;
+ Character.SecondRoleType = RoleType.None;
+ Character.ThirdRoleType = RoleType.None;
+ CombatTalent?.RemoveSkillFromCharacter(Character);
+ foreach (SubClass sc in SubClasses)
+ {
+ foreach (Skill skill in sc.InherentPassives)
+ {
+ skill.RemoveSkillFromCharacter(Character);
+ }
+ }
+ foreach (Class c in Classes)
+ {
+ foreach (Skill skill in c.PassiveSkills)
+ {
+ skill.RemoveSkillFromCharacter(Character);
+ }
+ foreach (Skill skill in c.Skills)
+ {
+ skill.RemoveSkillFromCharacter(Character);
+ }
+ foreach (Skill skill in c.Magics)
+ {
+ skill.RemoveSkillFromCharacter(Character);
+ }
+ foreach (Skill skill in c.SuperSkills)
+ {
+ skill.RemoveSkillFromCharacter(Character);
+ }
+ }
+ Classes.Clear();
+ SubClasses.Clear();
+ foreach (Class c in obj.Classes)
+ {
+ Classes.Add(c);
+ foreach (Skill skill in c.PassiveSkills)
+ {
+ skill.AddSkillToCharacter(Character);
+ }
+ foreach (Skill skill in c.Skills)
+ {
+ skill.AddSkillToCharacter(Character);
+ }
+ foreach (Skill skill in c.Magics)
+ {
+ skill.AddSkillToCharacter(Character);
+ }
+ foreach (Skill skill in c.SuperSkills)
+ {
+ skill.AddSkillToCharacter(Character);
+ }
+ }
+ foreach (SubClass sc in obj.SubClasses)
+ {
+ SubClasses.Add(sc);
+ foreach (Skill skill in sc.InherentPassives)
+ {
+ skill.AddSkillToCharacter(Character);
+ }
+ }
+ if (obj.CurrentCombatTalent != null)
+ {
+ CombatTalent = obj.CurrentCombatTalent;
+ CombatTalent.AddSkillToCharacter(Character);
+ }
+ }
+ }
+
+ ///
+ /// 决定如何构建角色的职业。这个类没有 JSON 转换器支持
+ ///
+ public class ClassObject(Class[] c, SubClass[] s)
+ {
+ public Class[] Classes { get; set; } = c;
+ public SubClass[] SubClasses { get; set; } = s;
+ public RoleType FirstRoleType { get; set; } = RoleType.None;
+ public RoleType SecondRoleType { get; set; } = RoleType.None;
+ public RoleType ThirdRoleType { get; set; } = RoleType.None;
+ public Skill? CurrentCombatTalent { get; set; } = null;
+ }
+}
diff --git a/Entity/Character/Class.cs b/Entity/Character/Class.cs
new file mode 100644
index 0000000..22d96b8
--- /dev/null
+++ b/Entity/Character/Class.cs
@@ -0,0 +1,55 @@
+using Milimoe.FunGame.Core.Interface.Entity;
+
+namespace Milimoe.FunGame.Core.Entity
+{
+ ///
+ /// 角色职业类
+ ///
+ public class Class : BaseEntity
+ {
+ ///
+ /// 职业名称
+ ///
+ public override string Name { get; set; } = "";
+
+ ///
+ /// 职业等级
+ ///
+ public int Level
+ {
+ get
+ {
+ return Math.Max(0, field);
+ }
+ set
+ {
+ field = Math.Max(0, value);
+ }
+ }
+
+ ///
+ /// 职业战技
+ ///
+ public HashSet Skills { get; set; } = [];
+
+ ///
+ /// 职业魔法
+ ///
+ public HashSet Magics { get; set; } = [];
+
+ ///
+ /// 职业被动
+ ///
+ public HashSet PassiveSkills { get; set; } = [];
+
+ ///
+ /// 职业爆发技
+ ///
+ public HashSet SuperSkills { get; set; } = [];
+
+ public override bool Equals(IBaseEntity? other)
+ {
+ return other is Class && other.GetIdName() == GetIdName();
+ }
+ }
+}
diff --git a/Entity/Character/SubClass.cs b/Entity/Character/SubClass.cs
new file mode 100644
index 0000000..c92d170
--- /dev/null
+++ b/Entity/Character/SubClass.cs
@@ -0,0 +1,46 @@
+using Milimoe.FunGame.Core.Interface.Entity;
+using Milimoe.FunGame.Core.Library.Constant;
+
+namespace Milimoe.FunGame.Core.Entity
+{
+ ///
+ /// 子职业(流派/派别)
+ ///
+ public class SubClass(Class @class) : BaseEntity
+ {
+ ///
+ /// 流派名称
+ ///
+ public override string Name { get; set; } = "";
+
+ ///
+ /// 所属职业
+ ///
+ public Class Class => @class;
+
+ ///
+ /// 职业等级
+ ///
+ public int Level => @class.Level;
+
+ ///
+ /// 固有被动
+ ///
+ public HashSet InherentPassives { get; set; } = [];
+
+ ///
+ /// 角色定位
+ ///
+ public HashSet RoleTypes { get; set; } = [];
+
+ ///
+ /// 战斗天赋
+ ///
+ public HashSet CombatTalents { get; set; } = [];
+
+ public override bool Equals(IBaseEntity? other)
+ {
+ return other is SubClass && other.GetIdName() == GetIdName();
+ }
+ }
+}
diff --git a/Entity/Item/Item.cs b/Entity/Item/Item.cs
index 5b69611..4dcd425 100644
--- a/Entity/Item/Item.cs
+++ b/Entity/Item/Item.cs
@@ -252,16 +252,11 @@ namespace Milimoe.FunGame.Core.Entity
{
foreach (Skill skill in Skills.Passives)
{
- List effects = [.. Character.Effects.Where(e => e.Skill == skill && e.IsInEffect).OrderByDescending(e => e.Priority)];
- foreach (Effect e in effects)
- {
- Character.Effects.Remove(e);
- e.OnEffectLost(Character);
- }
+ skill.RemoveSkillFromCharacter(Character);
}
foreach (Skill skill in Skills.Magics)
{
- Character.Skills.Remove(skill);
+ skill.RemoveSkillFromCharacter(Character);
}
switch (type)
{
diff --git a/Entity/Skill/Skill.cs b/Entity/Skill/Skill.cs
index 4408b2e..cb38b1d 100644
--- a/Entity/Skill/Skill.cs
+++ b/Entity/Skill/Skill.cs
@@ -56,7 +56,12 @@ namespace Milimoe.FunGame.Core.Entity
{
get
{
- return Math.Max(0, field + ExLevel);
+ int level = field + ExLevel;
+ if (MaxLevel > 0)
+ {
+ level = Math.Min(level, MaxLevel);
+ }
+ return Math.Max(0, level);
}
set
{
@@ -71,6 +76,11 @@ namespace Milimoe.FunGame.Core.Entity
///
public int ExLevel { get; set; } = 0;
+ ///
+ /// 自定义最大等级
+ ///
+ public int MaxLevel { get; set; } = 0;
+
///
/// 技能类型 [ 此项为最高优先级 ]
///
@@ -771,7 +781,7 @@ namespace Milimoe.FunGame.Core.Entity
}
///
- /// 被动技能,需要重写此方法,返回被动特效给角色 [ 此方法会在技能学习时触发 ]
+ /// 被动技能需要重写此方法,返回被动特效给角色 [ 此方法会在技能学习时触发 ]
///
///
public virtual IEnumerable AddPassiveEffectToCharacter()
@@ -779,6 +789,50 @@ namespace Milimoe.FunGame.Core.Entity
return [];
}
+ ///
+ /// 将技能添加到角色身上,如果是被动,则添加被动特效
+ ///
+ /// 角色
+ ///
+ public void AddSkillToCharacter(Character character)
+ {
+ if (Level > 0)
+ {
+ Character = character;
+ foreach (Effect e in AddPassiveEffectToCharacter())
+ {
+ e.GamingQueue = GamingQueue;
+ Character.Effects.Add(e);
+ e.OnEffectGained(Character);
+ }
+ // 如果是纯被动技能,则不会添加到角色技能组中
+ if (IsActive)
+ {
+ Character.Skills.Add(this);
+ }
+ }
+ }
+
+ ///
+ /// 从角色身上移除技能
+ ///
+ /// 角色
+ ///
+ public void RemoveSkillFromCharacter(Character character)
+ {
+ List effects = [.. character.Effects.Where(e => e.Skill == this).OrderByDescending(e => e.Priority)];
+ foreach (Effect e in effects)
+ {
+ character.Effects.Remove(e);
+ if (e.IsInEffect) e.OnEffectLost(character);
+ }
+ character.Skills.Remove(this);
+ if (character == Character)
+ {
+ Character = null;
+ }
+ }
+
///
/// 在复活时,因为复活是重新构建角色,如果需要继承死亡角色的技能数据,可以重写此方法并设置相关属性
///
diff --git a/Library/Common/JsonConverter/CharacterConverter.cs b/Library/Common/JsonConverter/CharacterConverter.cs
index 3310ac5..c66721b 100644
--- a/Library/Common/JsonConverter/CharacterConverter.cs
+++ b/Library/Common/JsonConverter/CharacterConverter.cs
@@ -62,6 +62,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
case nameof(Character.ExLevel):
result.ExLevel = reader.GetInt32();
break;
+ case nameof(Character.MaxLevel):
+ result.MaxLevel = reader.GetInt32();
+ break;
case nameof(Character.LevelBreak):
result.LevelBreak = reader.GetInt32();
break;
@@ -270,7 +273,8 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
writer.WriteNumber(nameof(Character.Promotion), value.Promotion);
writer.WriteNumber(nameof(Character.PrimaryAttribute), (int)value.PrimaryAttribute);
writer.WriteNumber(nameof(Character.Level), value.Level);
- writer.WriteNumber(nameof(Character.ExLevel), value.ExLevel);
+ if (value.ExLevel > 0) writer.WriteNumber(nameof(Character.ExLevel), value.ExLevel);
+ if (value.MaxLevel > 0) writer.WriteNumber(nameof(Character.MaxLevel), value.MaxLevel);
writer.WriteNumber(nameof(Character.LevelBreak), value.LevelBreak);
writer.WriteNumber(nameof(Character.EXP), value.EXP);
writer.WriteBoolean(nameof(Character.IsNeutral), value.IsNeutral);
diff --git a/Library/Common/JsonConverter/SkillConverter.cs b/Library/Common/JsonConverter/SkillConverter.cs
index 2e3f89f..eef7a5c 100644
--- a/Library/Common/JsonConverter/SkillConverter.cs
+++ b/Library/Common/JsonConverter/SkillConverter.cs
@@ -44,6 +44,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
case nameof(Skill.ExLevel):
result.ExLevel = reader.GetInt32();
break;
+ case nameof(Skill.MaxLevel):
+ result.MaxLevel = reader.GetInt32();
+ break;
case nameof(Skill.CastAnywhere):
result.CastAnywhere = reader.GetBoolean();
break;
@@ -147,6 +150,7 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
if (value.Slogan.Length > 0) writer.WriteString(nameof(Skill.Slogan), value.Slogan);
if (value.Level > 0) writer.WriteNumber(nameof(Skill.Level), value.Level);
if (value.ExLevel > 0) writer.WriteNumber(nameof(Skill.ExLevel), value.ExLevel);
+ if (value.MaxLevel > 0) writer.WriteNumber(nameof(Skill.MaxLevel), value.MaxLevel);
writer.WriteBoolean(nameof(Skill.CastAnywhere), value.CastAnywhere);
writer.WriteNumber(nameof(Skill.CastRange), value.CastRange);
if (value.CanSelectSelf) writer.WriteBoolean(nameof(Skill.CanSelectSelf), value.CanSelectSelf);
diff --git a/Model/EquilibriumConstant.cs b/Model/EquilibriumConstant.cs
index a931d35..8f0b118 100644
--- a/Model/EquilibriumConstant.cs
+++ b/Model/EquilibriumConstant.cs
@@ -635,6 +635,11 @@ namespace Milimoe.FunGame.Core.Model
///
public int DecisionPointsCostOther { get; set; } = 1;
+ ///
+ /// 角色升级时会获得职业点数,该属性设置可获得点数的等级
+ ///
+ public HashSet ClassPointsGetterList { get; set; } = [1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55];
+
///
/// 应用此游戏平衡常数给实体
///
diff --git a/Model/PrefabricatedEntity/MagicCardPack.cs b/Model/PrefabricatedEntity/MagicCardPack.cs
index 5fc6592..d19a338 100644
--- a/Model/PrefabricatedEntity/MagicCardPack.cs
+++ b/Model/PrefabricatedEntity/MagicCardPack.cs
@@ -122,16 +122,10 @@ namespace Milimoe.FunGame.Core.Model.PrefabricatedEntity
if (NeuralCalibration != null)
{
character.Effects.Remove(NeuralCalibration);
- NeuralCalibration.OnEffectLost(character);
- }
- if (CourageCommand != null)
- {
- character.Skills.Remove(CourageCommand);
- }
- if (Soulbound != null)
- {
- character.Skills.Remove(Soulbound);
+ if (NeuralCalibration.IsInEffect) NeuralCalibration.OnEffectLost(character);
}
+ CourageCommand?.RemoveSkillFromCharacter(character);
+ Soulbound?.RemoveSkillFromCharacter(character);
}
}
}