Campofinale/Campofinale/Game/Character/Character.cs
AlessandroCH 0c268cb978 fix
2025-03-09 16:56:48 +01:00

485 lines
18 KiB
C#

using Campofinale.Game.Inventory;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
using Google.Protobuf.Collections;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.IdGenerators;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using static Campofinale.Resource.ResourceManager;
using static Campofinale.Resource.ResourceManager.CharGrowthTable;
using static Campofinale.Resource.ResourceManager.WeaponUpgradeTemplateTable;
namespace Campofinale.Game.Character
{
public class Character
{
[BsonId(IdGenerator = typeof(ObjectIdGenerator))]
public ObjectId _id { get; set; }
[BsonElement("templateId")]
public string id;
public ulong guid;
public ulong weaponGuid;
public int level;
public int xp;
public ulong owner;
public double curHp;
public float ultimateSp = 200;
public uint potential = 0;
public string breakNode = "charBreak20";
public List<string> passiveSkillNodes = new();
public List<string> attrNodes = new();
public List<string> factoryNodes = new();
public Dictionary<int,ulong> equipCol = new() { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 } };
public Character()
{
}
public Character(ulong owner, string id) : this(owner, id, 1)
{
}
public Dictionary<AttributeType, (double baseVal, double val)> CalcAttributes()
{
Dictionary<AttributeType, (double baseVal, double val)> attributes = new();
foreach (var item in GetAttributes())
{
attributes.Add((AttributeType)item.attrType, (item.attrValue, item.attrValue));
}
Item weapon = GetOwner().inventoryManager.items.Find(w => w.guid == weaponGuid);
if(weapon != null)
{
WeaponBasicTable wTable = ResourceManager.weaponBasicTable[weapon.id];
WeaponUpgradeTemplateTable template = ResourceManager.weaponUpgradeTemplateTable[wTable.levelTemplateId];
WeaponCurve curve=template.list.Find(c => c.weaponLv == weapon.level);
attributes[AttributeType.Atk] = (attributes[AttributeType.Atk].baseVal + curve.baseAtk, attributes[AttributeType.Atk].baseVal + curve.baseAtk);
}
//Won't be very precise but for now
foreach (var equip in equipCol)
{
Item EquipItem = GetOwner().inventoryManager.items.Find(e => e.guid == equip.Value);
if (EquipItem != null)
{
foreach (var modifier in EquipItem.GetEquipAttributeModifier())
{
switch (modifier.modifierType)
{
case ModifierType.BaseAddition:
case ModifierType.Addition:
attributes=SetValueDic(attributes, modifier.attrType, GetValueDic(attributes, modifier.attrType) + modifier.attrValue);
break;
case ModifierType.Multiplier:
case ModifierType.BaseMultiplier:
attributes=SetValueDic(attributes, modifier.attrType, GetValueDic(attributes, modifier.attrType) * 1 + modifier.attrValue);
break;
default:
break;
}
}
}
}
attributes[AttributeType.MaxHp] = (attributes[AttributeType.MaxHp].baseVal, attributes[AttributeType.MaxHp].val + attributes[AttributeType.Str].val * 10);
return attributes;
}
public double GetValueDic(Dictionary<AttributeType, (double baseVal, double val)> dic, AttributeType type)
{
if (dic.ContainsKey(type))
{
return dic[type].val;
}
return 0;
}
public Dictionary<AttributeType, (double baseVal, double val)> SetValueDic(Dictionary<AttributeType, (double baseVal, double val)> dic,AttributeType type,double value)
{
if (dic.ContainsKey(type))
{
dic[type] = (dic[type].baseVal,value);
}
else
{
dic.Add(type, (0, value));
}
return dic;
}
public void UnlockNode(string nodeId)
{
CharTalentNode nodeInfo = ResourceManager.GetTalentNode(id, nodeId);
if (nodeInfo == null) return;
//TODO remove cost items
switch (nodeInfo.nodeType)
{
case TalentNodeType.CharBreak:
breakNode = nodeId;
break;
case TalentNodeType.EquipBreak:
breakNode = nodeId;
break;
case TalentNodeType.Attr:
attrNodes.Add(nodeId);
break;
case TalentNodeType.PassiveSkill:
passiveSkillNodes.Add(nodeId);
break;
case TalentNodeType.FactorySkill:
factoryNodes.Add(nodeId);
break;
default:
Logger.PrintWarn($"Unimplemented NodeType {nodeInfo.nodeType}, not unlocked server side.");
break;
}
GetOwner().Send(new PacketScCharUnlockTalentNode(GetOwner(), this,nodeId));
}
public Character(ulong owner,string id, int level) : this()
{
this.owner = owner;
this.id = id;
this.level = level;
guid = GetOwner().random.Next();
this.weaponGuid = GetOwner().inventoryManager.AddWeapon(ResourceManager.charGrowthTable[id].defaultWeaponId, 1).guid;
this.curHp = CalcAttributes()[AttributeType.MaxHp].val;
if (level < 20) breakNode = "";
if (level >= 20 && level <= 40) breakNode = "charBreak20";
if (level > 40 && level <= 60) breakNode = "charBreak40";
if (level > 60 && level <= 70) breakNode = "charBreak60";
if (level > 70) breakNode = "charBreak70";
}
public int GetSkillMaxLevel()
{
if (GetBreakStage() == 0)
{
return 1;
}else if (GetBreakStage() == 1)
{
return 3;
}
else if (GetBreakStage() == 2)
{
return 6;
}
else if (GetBreakStage() == 3)
{
return 9;
}
else if (GetBreakStage() == 4)
{
return 12;
}
else
{
return 12;
}
}
public List<ResourceManager.Attribute> GetAttributes()
{
int lev = level - 1 + GetBreakStage();
return ResourceManager.characterTable[id].attributes[lev].Attribute.attrs;
}
public Player GetOwner()
{
return Server.clients.Find(c=>c.roleId == this.owner);
}
public SceneCharacter ToSceneProto()
{
SceneCharacter proto= new SceneCharacter()
{
Level = level,
BattleInfo = new()
{
MsgGeneration = 1,
SkillList =
{
new ServerSkill()
{
Blackboard = new()
{
},
InstId=GetOwner().random.Next(),
Level=GetSkillMaxLevel(),
Source=BattleSkillSource.Default,
PotentialLv=GetSkillMaxLevel(),
SkillId=id+"_NormalSkill",
},
new ServerSkill()
{
Blackboard = new()
{
},
InstId=GetOwner().random.Next(),
Level=GetSkillMaxLevel(),
Source=BattleSkillSource.Default,
PotentialLv=GetSkillMaxLevel(),
SkillId=id+"_ComboSkill",
},
new ServerSkill()
{
Blackboard = new()
{
},
InstId=GetOwner().random.Next(),
Level=GetSkillMaxLevel(),
Source=BattleSkillSource.Default,
PotentialLv=GetSkillMaxLevel(),
SkillId=id+"_UltimateSkill",
},
new ServerSkill()
{
Blackboard = new()
{
},
InstId=GetOwner().random.Next(),
Level=GetSkillMaxLevel(),
Source=BattleSkillSource.Default,
PotentialLv=GetSkillMaxLevel(),
SkillId=id+"_NormalAttack",
}
}
},
Name = $"{ResourceManager.characterTable[id].engName}",
CommonInfo = new()
{
Hp = curHp,
Id = guid,
Position = GetOwner().position.ToProto(),
Rotation = GetOwner().rotation.ToProto(),
SceneNumId = GetOwner().curSceneNumId,
Templateid = id,
Type = (int)0,
},
Attrs =
{
}
};
foreach(var attr in CalcAttributes())
{
proto.Attrs.Add(new AttrInfo()
{
AttrType = (int)attr.Key,
BasicValue = attr.Value.baseVal,
Value = attr.Value.val
});
}
return proto;
}
public int GetBreakStage()
{
if (ResourceManager.charBreakNodeTable.ContainsKey(breakNode))
{
int breakStage = ResourceManager.charBreakNodeTable[breakNode].breakStage;
return breakStage;
}
else
{
return 0;
}
}
public bool IsEquipped(ulong equipGuid)
{
return equipCol.Values.Contains(equipGuid);
}
public Dictionary<int,ulong> GetEquipCol()
{
Dictionary<int, ulong> equips = new();
foreach(var item in equipCol)
{
if (item.Value != 0)
{
equips.Add(item.Key,item.Value);
}
}
return equips;
}
public CharInfo ToProto()
{
CharInfo info = new CharInfo()
{
Exp = xp,
Level = level,
IsDead = curHp < 1,
Objid = guid,
Templateid = id,
CharType = CharType.DefaultType,
OwnTime = 1,
NormalSkill = id + "_NormalSkill",
WeaponId = weaponGuid,
PotentialLevel = potential,
EquipCol =
{
GetEquipCol()
},
Talent = new()
{
LatestBreakNode= breakNode,
LatestPassiveSkillNodes =
{
passiveSkillNodes
},
AttrNodes =
{
attrNodes
},
LatestFactorySkillNodes =
{
factoryNodes
}
},
BattleMgrInfo = new()
{
},
BattleInfo = new()
{
Hp = curHp,
Ultimatesp= ultimateSp,
},
SkillInfo = new()
{
NormalSkill = id + "_NormalSkill",
ComboSkill = id + "_ComboSkill",
UltimateSkill = id + "_UltimateSkill",
DispNormalAttackSkill = id + "_NormalAttack",
LevelInfo =
{
new SkillLevelInfo()
{
SkillId=id+"_NormalAttack",
SkillLevel=GetSkillMaxLevel(),
SkillMaxLevel=GetSkillMaxLevel(),
SkillEnhancedLevel=GetSkillMaxLevel()
},
new SkillLevelInfo()
{
SkillId=id+"_NormalSkill",
SkillLevel=GetSkillMaxLevel(),
SkillMaxLevel=GetSkillMaxLevel(),
SkillEnhancedLevel=GetSkillMaxLevel()
},
new SkillLevelInfo()
{
SkillId=id+"_UltimateSkill",
SkillLevel=GetSkillMaxLevel(),
SkillMaxLevel=GetSkillMaxLevel(),
SkillEnhancedLevel=GetSkillMaxLevel()
},
new SkillLevelInfo()
{
SkillId=id+"_ComboSkill",
SkillLevel=GetSkillMaxLevel(),
SkillMaxLevel=GetSkillMaxLevel(),
SkillEnhancedLevel=GetSkillMaxLevel()
},
}
}
};
Item wep = GetOwner().inventoryManager.items.Find(w => w.guid == weaponGuid);
if (wep != null)
{
//TODO weapon skills
}
foreach (ulong equipGuid in equipCol.Values)
{
Item item = GetOwner().inventoryManager.items.Find(i => i.guid == equipGuid);
if (item != null)
{
string equipSuitId = ResourceManager.GetEquipSuitTableKey(item.id);
if (equipSuitId.Length > 0)
{
if (info.EquipSuit.ContainsKey(equipSuitId))
{
info.EquipSuit[equipSuitId] += 1;
}
else
{
info.EquipSuit.Add(equipSuitId, 1);
}
}
}
}
return info;
}
public (int,int,int) CalculateLevelAndGoldCost(int addedXp)
{
int gold = 0;
int curLevel = this.level;
while(addedXp >= ResourceManager.charLevelUpTable["" + curLevel].exp)
{
gold += ResourceManager.charLevelUpTable["" + curLevel].gold;
addedXp -= ResourceManager.charLevelUpTable["" + curLevel].exp;
curLevel++;
if(curLevel >= 80)
{
curLevel = 80;
}
}
return (curLevel, gold, addedXp);
}
public void LevelUp(RepeatedField<ItemInfo> items)
{
int addedXp = 0;
foreach (var item in items)
{
addedXp += ResourceManager.expItemDataMap[item.ResId].expGain * item.ResCount;
}
(int, int, int) CalculatedValues = CalculateLevelAndGoldCost(xp+addedXp);
items.Add(new ItemInfo()
{
ResId = "item_gold",
ResCount = CalculatedValues.Item2
});
if (GetOwner().inventoryManager.ConsumeItems(items))
{
this.level = CalculatedValues.Item1;
this.xp= CalculatedValues.Item3;
ScCharLevelUp levelUp = new()
{
CharObjID = guid,
};
ScCharSyncLevelExp synclevel = new()
{
Exp = xp,
CharObjID = guid,
Level = level
};
GetOwner().Send(ScMsgId.ScCharSyncLevelExp, synclevel);
GetOwner().Send(ScMsgId.ScCharLevelUp, levelUp);
GetOwner().Send(new PacketScSyncWallet(GetOwner()));
}
}
}
}