Compare commits

...

2 Commits

Author SHA1 Message Date
AlessandroCH
96048df57c CsSceneRest fix, teleport improvements, cache max item amount now is 50 2025-08-08 23:05:37 +02:00
AlessandroCH
388a71df7f CsSceneRest 2025-08-08 19:06:50 +02:00
17 changed files with 175 additions and 140 deletions

View File

@ -10,21 +10,8 @@ namespace Campofinale.Commands.Handlers
[Server.Command("heal", "Revives/Heals your team characters", true)] [Server.Command("heal", "Revives/Heals your team characters", true)]
public static void Handle(Player sender, string cmd, string[] args, Player target) public static void Handle(Player sender, string cmd, string[] args, Player target)
{ {
target.GetCurTeam().ForEach(chara => target.RestTeam();
{
chara.curHp = chara.CalcAttributes()[AttributeType.MaxHp].val;
ScCharSyncStatus state = new ScCharSyncStatus()
{
Objid=chara.guid,
IsDead=chara.curHp < 1,
BattleInfo = new()
{
Hp=chara.curHp,
Ultimatesp=chara.ultimateSp
}
};
target.Send(ScMsgId.ScCharSyncStatus, state);
});
target.Send(ScMsgId.ScSceneRevival, new ScSceneRevival() target.Send(ScMsgId.ScSceneRevival, new ScSceneRevival()
{ {

View File

@ -80,7 +80,7 @@ namespace Campofinale.Game.Factory.BuildingsBehaviour
producer.lastFormulaId = recipe; producer.lastFormulaId = recipe;
producer.progress += craftingRecipe.totalProgress/craftingRecipe.progressRound; producer.progress += craftingRecipe.totalProgress/craftingRecipe.progressRound;
currentProgress++; currentProgress++;
if (currentProgress >= craftingRecipe.progressRound) if (currentProgress >= craftingRecipe.progressRound)
{ {
currentProgress = 0; currentProgress = 0;

View File

@ -61,7 +61,7 @@ namespace Campofinale.Game.Factory.Components
public bool IsFull() public bool IsFull()
{ {
int maxItems = items.Count * 100; int maxItems = items.Count * 50;
int count = 0; int count = 0;
foreach (var item in items) foreach (var item in items)
{ {
@ -75,7 +75,7 @@ namespace Campofinale.Game.Factory.Components
int remaining = count; int remaining = count;
foreach (var item in items) foreach (var item in items)
{ {
int space = 100-item.count; int space = 50-item.count;
if (item.id==id) if (item.id==id)
{ {
if (space >= remaining) if (space >= remaining)

View File

@ -24,7 +24,7 @@ namespace Campofinale.Game.Factory
ScFactorySyncChapter chapter = new() ScFactorySyncChapter chapter = new()
{ {
ChapterId = chapterId, ChapterId = chapterId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds() / 1000, Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(),
Blackboard = new() Blackboard = new()
{ {
Power = new() Power = new()
@ -40,11 +40,12 @@ namespace Campofinale.Game.Factory
{ {
LastDay = new() LastDay = new()
{ {
}, },
Other = new() Other = new()
{ {
InPowerBuilding = 1 InPowerBuilding = nodes.FindAll(n=>n.lastPowered==true).Count,
} }
}, },
PinBoard = new() PinBoard = new()
@ -75,7 +76,7 @@ namespace Campofinale.Game.Factory
Current = 0, Current = 0,
Max = sceneGrade.bandwidth, Max = sceneGrade.bandwidth,
TravelPoleMax = sceneGrade.travelPoleLimit, TravelPoleMax = sceneGrade.travelPoleLimit,
BattleCurrent = 0, BattleCurrent = 0,
BattleMax = sceneGrade.battleBuildingLimit, BattleMax = sceneGrade.battleBuildingLimit,
}, },
@ -152,10 +153,12 @@ namespace Campofinale.Game.Factory
maps.Add(new ScdFactorySyncMap() maps.Add(new ScdFactorySyncMap()
{ {
MapId = ResourceManager.strIdNumTable.chapter_map_id.dic[mapId], MapId = ResourceManager.strIdNumTable.chapter_map_id.dic[mapId],
Wires = Wires =
{ {
GetWires() GetWires()
} },
}); });
return maps; return maps;
} }
@ -181,7 +184,8 @@ namespace Campofinale.Game.Factory
{ {
Index = i, Index = i,
FromComId = compA, FromComId = compA,
ToComId = compB ToComId = compB,
}); });
addedConnections.Add(key); addedConnections.Add(key);
@ -243,6 +247,9 @@ namespace Campofinale.Game.Factory
case FactoryOpType.MoveItemBagToCache: case FactoryOpType.MoveItemBagToCache:
MoveItemBagToCache(op, seq); MoveItemBagToCache(op, seq);
break; break;
case FactoryOpType.MoveItemCacheToBag:
MoveItemCacheToBag(op, seq);
break;
case FactoryOpType.ChangeProducerMode: case FactoryOpType.ChangeProducerMode:
ChangeProducerMode(op, seq); ChangeProducerMode(op, seq);
break; break;
@ -255,6 +262,9 @@ namespace Campofinale.Game.Factory
case FactoryOpType.DismantleBoxConveyor: case FactoryOpType.DismantleBoxConveyor:
DismantleBoxConveyor(op, seq); DismantleBoxConveyor(op, seq);
break; break;
case FactoryOpType.UseHealTowerPoint:
//TODO
break;
case FactoryOpType.SetTravelPoleDefaultNext: case FactoryOpType.SetTravelPoleDefaultNext:
FactoryNode travelNode = GetNodeByCompId(op.SetTravelPoleDefaultNext.ComponentId); FactoryNode travelNode = GetNodeByCompId(op.SetTravelPoleDefaultNext.ComponentId);
travelNode.GetComponent<FComponentTravelPole>().defaultNext = op.SetTravelPoleDefaultNext.DefaultNext; travelNode.GetComponent<FComponentTravelPole>().defaultNext = op.SetTravelPoleDefaultNext.DefaultNext;
@ -283,7 +293,7 @@ namespace Campofinale.Game.Factory
ScFactoryOpRet ret = new() ScFactoryOpRet ret = new()
{ {
RetCode = FactoryOpRetCode.Fail, RetCode = FactoryOpRetCode.Fail,
}; };
GetOwner().Send(ScMsgId.ScFactoryOpRet, ret, seq); GetOwner().Send(ScMsgId.ScFactoryOpRet, ret, seq);
} }
@ -315,6 +325,49 @@ namespace Campofinale.Game.Factory
GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), 0, op), seq); GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), 0, op), seq);
} }
public void MoveItemCacheToBag(CsFactoryOp op, ulong seq)
{
var move = op.MoveItemCacheToBag;
FComponentCache cacheComp = GetCompById<FComponentCache>(move.ComponentId);
if (cacheComp != null)
{
ItemCount cacheItem = cacheComp.items[move.CacheGridIndex];
Item gridItem = null;
GetOwner().inventoryManager.items.bag.TryGetValue(move.GridIndex, out gridItem);
if (gridItem == null)
{
GetOwner().inventoryManager.items.bag.Add(move.GridIndex, new Item(ownerId,cacheItem.id,cacheItem.count));
cacheItem.id = "";
cacheItem.count = 0;
}
else
{
if(gridItem.id == cacheItem.id)
{
int availableSpace = 50 - gridItem.amount;
if(cacheItem.count > availableSpace)
{
gridItem.amount += availableSpace;
cacheItem.count-= availableSpace;
}
else
{
gridItem.amount += cacheItem.count;
cacheItem.id = "";
cacheItem.count = 0;
}
}
else
{
//TODO Swap
}
}
}
GetOwner().inventoryManager.items.UpdateBagInventoryPacket();
GetOwner().Send(new PacketScFactoryOpRet(GetOwner(), 0, op), seq);
}
public void MoveItemBagToCache(CsFactoryOp op, ulong seq) public void MoveItemBagToCache(CsFactoryOp op, ulong seq)
{ {
var move = op.MoveItemBagToCache; var move = op.MoveItemBagToCache;
@ -327,7 +380,7 @@ namespace Campofinale.Game.Factory
{ {
if(cacheComp.items[move.CacheGridIndex].id == "" || cacheComp.items[move.CacheGridIndex].id == gridItem.id) if(cacheComp.items[move.CacheGridIndex].id == "" || cacheComp.items[move.CacheGridIndex].id == gridItem.id)
{ {
int canAdd = 100 - cacheComp.items[move.CacheGridIndex].count; int canAdd = 50 - cacheComp.items[move.CacheGridIndex].count;
if (canAdd >= gridItem.amount) if (canAdd >= gridItem.amount)
{ {
@ -385,7 +438,7 @@ namespace Campofinale.Game.Factory
{ {
ChapterId = chapterId, ChapterId = chapterId,
MapId = nodeRem.mapId, MapId = nodeRem.mapId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds() / 1000, Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(),
Wires = Wires =
{ {
GetWires() GetWires()
@ -468,7 +521,7 @@ namespace Campofinale.Game.Factory
{ {
ChapterId = chapterId, ChapterId = chapterId,
MapId = GetNodeByCompId(nodeFrom.compId).mapId, MapId = GetNodeByCompId(nodeFrom.compId).mapId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds() / 1000, Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(),
Wires = Wires =
{ {
GetWires() GetWires()
@ -552,7 +605,6 @@ namespace Campofinale.Game.Factory
public void PlaceConveyor(CsFactoryOp op, ulong seq) public void PlaceConveyor(CsFactoryOp op, ulong seq)
{ {
var placeConveyor = op.PlaceConveyor; var placeConveyor = op.PlaceConveyor;
Logger.Print($"'PlaceConveyor': {JsonConvert.SerializeObject(placeConveyor)}");
v++; v++;
uint nodeId = v; uint nodeId = v;
List<Vector3f> points = new(); List<Vector3f> points = new();

View File

@ -72,6 +72,7 @@ namespace Campofinale.Game.Factory
public void SendFactoryHsSync() public void SendFactoryHsSync()
{ {
if (!player.Initialized) return; if (!player.Initialized) return;
if (player.GetCurrentChapter() == "") return;
long curtimestamp = DateTime.UtcNow.ToUnixTimestampMilliseconds(); long curtimestamp = DateTime.UtcNow.ToUnixTimestampMilliseconds();
ScFactoryHsSync hs = new() ScFactoryHsSync hs = new()

View File

@ -78,6 +78,15 @@ namespace Campofinale.Game.Factory
} }
} }
public FactoryBuildingTable GetBuildingTable()
{
ResourceManager.factoryBuildingTable.TryGetValue(templateId, out FactoryBuildingTable table);
if (table == null)
{
table = new FactoryBuildingTable();
}
return table;
}
public void UpdatePortManager(FactoryChapter chapter,FComponentPortManager manager) public void UpdatePortManager(FactoryChapter chapter,FComponentPortManager manager)
{ {
if (ResourceManager.factoryBuildingTable.TryGetValue(templateId, out FactoryBuildingTable table)) if (ResourceManager.factoryBuildingTable.TryGetValue(templateId, out FactoryBuildingTable table))
@ -213,7 +222,6 @@ namespace Campofinale.Game.Factory
conveyorComp.items.Add(i); conveyorComp.items.Add(i);
i.tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(); i.tms = DateTime.UtcNow.ToUnixTimestampMilliseconds();
conveyorComp.lastPopTms = i.tms; conveyorComp.lastPopTms = i.tms;
Logger.Print("Spawning item in conveyor: " + conveyorComp.lastPopTms);
return true; return true;
} }
else else
@ -250,7 +258,6 @@ namespace Campofinale.Game.Factory
if (originalPorts == null || originalPorts.Count == 0) if (originalPorts == null || originalPorts.Count == 0)
return transformedPorts; return transformedPorts;
// Ottieni la posizione e rotazione base dall'oggetto
FMesh mesh = GetMesh(); FMesh mesh = GetMesh();
if (mesh.points.Count < 2) if (mesh.points.Count < 2)
return transformedPorts; return transformedPorts;
@ -258,7 +265,6 @@ namespace Campofinale.Game.Factory
Vector3f objectPosition = mesh.points[0]; Vector3f objectPosition = mesh.points[0];
float objectRotationY = direction.y % 360f; float objectRotationY = direction.y % 360f;
// Ottieni le dimensioni originali
FactoryBuildingTable table; FactoryBuildingTable table;
if (!ResourceManager.factoryBuildingTable.TryGetValue(templateId, out table)) if (!ResourceManager.factoryBuildingTable.TryGetValue(templateId, out table))
return transformedPorts; return transformedPorts;
@ -300,7 +306,6 @@ namespace Campofinale.Game.Factory
transformedPort.trans.position = transformedPos; transformedPort.trans.position = transformedPos;
// Rotazione della porta
transformedPort.trans.rotation = new Vector3f( transformedPort.trans.rotation = new Vector3f(
originalPort.trans.rotation.x, originalPort.trans.rotation.x,
(originalPort.trans.rotation.y + objectRotationY) % 360f, (originalPort.trans.rotation.y + objectRotationY) % 360f,
@ -381,6 +386,8 @@ namespace Campofinale.Game.Factory
{ {
InPower = InPower(), InPower = InPower(),
NeedInPower = true, NeedInPower = true,
PowerCost= GetBuildingTable().bandwidth,
PowerCostShow= GetBuildingTable().bandwidth,
}, },
NodeType = (int)nodeType, NodeType = (int)nodeType,

View File

@ -27,8 +27,18 @@ namespace Campofinale.Game
} }
public void Update() public void Update()
{ {
if (GetCurScene()!=null) if (GetCurScene() != null)
GetCurScene().UpdateShowEntities(); {
try
{
GetCurScene().UpdateShowEntities();
}
catch(Exception e)
{
}
}
} }
public Entity GetEntity(ulong guid) public Entity GetEntity(ulong guid)
{ {

View File

@ -15,6 +15,7 @@ namespace Campofinale.Packets.Cs
Character character = session.chars.Find(c => c.guid == req.CharObjId); Character character = session.chars.Find(c => c.guid == req.CharObjId);
if (character != null) if (character != null)
{ {
character.potential=req.Level; character.potential=req.Level;
//TODO consume Item ID //TODO consume Item ID

View File

@ -19,107 +19,6 @@ namespace Campofinale.Packets.Cs
CsGachaTenPullReq req = packet.DecodeBody<CsGachaTenPullReq>(); CsGachaTenPullReq req = packet.DecodeBody<CsGachaTenPullReq>();
session.gachaManager.upSeqId = packet.csHead.UpSeqid; session.gachaManager.upSeqId = packet.csHead.UpSeqid;
session.gachaManager.DoGacha(req.GachaPoolId, 10); session.gachaManager.DoGacha(req.GachaPoolId, 10);
/* Random rng = new Random();
List<string> chars = new List<string>();
const double prob6Star = 0.008; // 0.8%
const double prob5Star = 0.08; // 8%
const double fiftyfifty = 0.50; // 50%
GachaCharPoolTable table = ResourceManager.gachaCharPoolTable[req.GachaPoolId];
GachaCharPoolContentTable content = ResourceManager.gachaCharPoolContentTable[req.GachaPoolId];
int sixstarcount = 0;
int fivestarcount = 0;
List<GachaCharPoolItem> fiveStars = content.list.FindAll(c => c.starLevel == 5);
List<GachaCharPoolItem> sixStars = content.list.FindAll(c => c.starLevel == 6);
int fiveStarGuaranteedIndex = new Random().Next(9);
for (int i=0; i < 10; i++)
{
double roll = rng.NextDouble();
double fifty = rng.NextDouble();
if (roll < prob6Star)
{
sixstarcount++;
if (table.upCharIds.Count > 0)
{
if (fifty >= fiftyfifty)
{
chars.Add(ResourceManager.characterTable[table.upCharIds[0]].charId);
}
else
{
chars.Add(sixStars[new Random().Next(sixStars.Count - 1)].charId);
}
}
else
{
chars.Add(sixStars[new Random().Next(sixStars.Count - 1)].charId);
}
}
else if (roll < prob6Star + prob5Star || fiveStarGuaranteedIndex == i)
{
fivestarcount++;
if(table.upCharIds.Count > 1)
{
if(fifty >= fiftyfifty)
{
chars.Add(ResourceManager.characterTable[table.upCharIds[1]].charId);
}
else
{
chars.Add(fiveStars[new Random().Next(fiveStars.Count - 1)].charId);
}
}
else
{
chars.Add(fiveStars[new Random().Next(fiveStars.Count-1)].charId);
}
}
else
{
chars.Add(ResourceManager.characterTable.Values.ToList().FindAll(c=>c.rarity == 4)[new Random().Next(ResourceManager.characterTable.Values.ToList().FindAll(c => c.rarity == 4).Count - 1)].charId);
}
}
ScGachaSyncPullResult result = new ScGachaSyncPullResult()
{
GachaPoolId=req.GachaPoolId,
GachaType=req.GachaType,
OriResultIds =
{
},
Star5GotCount= fivestarcount,
Star6GotCount= sixstarcount,
FinalResults =
{
},
UpGotCount= fivestarcount+ sixstarcount,
};
foreach(string ch in chars)
{
bool exist = session.chars.Find(c => c.id == ch) != null;
result.OriResultIds.Add(ch);
result.FinalResults.Add(new ScdGachaFinalResult()
{
IsNew= !exist,
ItemId=ch,
});
}
//session.Send(Packet.EncodePacket((int)CsMessageId.CsGachaTenPullReq, req));
session.Send(ScMessageId.ScGachaSyncPullResult, result); */
// session.Send(CsMessageId.CsGachaEnd, new Empty());
// session.Send(ScMessageId.ScGachaBegin, new Empty());
} }
} }

View File

@ -12,6 +12,7 @@ namespace Campofinale.Packets.Cs
public static void Handle(Player session, CsMsgId cmdId, Packet packet) public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{ {
CsMoveObjectMove req = packet.DecodeBody<CsMoveObjectMove>(); CsMoveObjectMove req = packet.DecodeBody<CsMoveObjectMove>();
if (session.sceneLoadState != Player.SceneLoadState.OK) return;
foreach (var moveInfo in req.MoveInfo) foreach (var moveInfo in req.MoveInfo)
{ {

View File

@ -1,5 +1,7 @@
using Campofinale.Network; using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol; using Campofinale.Protocol;
using Campofinale.Resource;
namespace Campofinale.Packets.Cs namespace Campofinale.Packets.Cs
{ {
@ -30,6 +32,7 @@ namespace Campofinale.Packets.Cs
} }
// Not correctly fixed, need to find the issue - SuikoAkari // Not correctly fixed, need to find the issue - SuikoAkari
// No idea how pass_through_data is used, it's not part of the packet sent by the official server // No idea how pass_through_data is used, it's not part of the packet sent by the official server
session.Send(new PacketScSelfSceneInfo(session, SelfInfoReasonType.SlrReviveRest));
session.Send(ScMsgId.ScSceneRepatriate, new ScSceneRepatriate() session.Send(ScMsgId.ScSceneRepatriate, new ScSceneRepatriate()
{ {
SceneNumId = session.savedSaveZone.sceneNumId, SceneNumId = session.savedSaveZone.sceneNumId,

View File

@ -0,0 +1,28 @@
using Campofinale.Network;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using Campofinale.Resource;
namespace Campofinale.Packets.Cs
{
public class HandleCsSceneRest
{
[Server.Handler(CsMsgId.CsSceneRest)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsSceneRest req = packet.DecodeBody<CsSceneRest>();
if (session.sceneLoadState == Player.SceneLoadState.Loading) return;
ScSceneRevival revival = new()
{
};
session.RestTeam();
session.sceneManager.LoadCurrentTeamEntities();
session.Send(ScMsgId.ScSceneRevival, revival, packet.csHead.UpSeqid);
session.Send(new PacketScSelfSceneInfo(session, SelfInfoReasonType.SlrReviveRest));
}
}
}

View File

@ -1,6 +1,7 @@
using Campofinale.Network; using Campofinale.Network;
using Campofinale.Protocol; using Campofinale.Protocol;
using Campofinale.Utils; using Campofinale.Utils;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Packets.Cs namespace Campofinale.Packets.Cs
{ {
@ -15,7 +16,7 @@ namespace Campofinale.Packets.Cs
if (session.curSceneNumId != req.SceneNumId) if (session.curSceneNumId != req.SceneNumId)
{ {
session.EnterScene(req.SceneNumId, new Resource.ResourceManager.Vector3f(req.Position), new Resource.ResourceManager.Vector3f(req.Rotation)); session.EnterScene(req.SceneNumId, new Resource.ResourceManager.Vector3f(req.Position), new Resource.ResourceManager.Vector3f(req.Rotation));
/* ScSceneTeleport t = new() ScSceneTeleport t = new()
{ {
TeleportReason = req.TeleportReason, TeleportReason = req.TeleportReason,
PassThroughData = req.PassThroughData, PassThroughData = req.PassThroughData,
@ -23,7 +24,7 @@ namespace Campofinale.Packets.Cs
Rotation = req.Rotation, Rotation = req.Rotation,
SceneNumId = req.SceneNumId, SceneNumId = req.SceneNumId,
}; };
session.Send(ScMsgId.ScSceneTeleport, t);*/ session.Send(ScMsgId.ScSceneTeleport, t);
} }
else else
{ {
@ -41,6 +42,9 @@ namespace Campofinale.Packets.Cs
TpUuid= (ulong)id TpUuid= (ulong)id
}; };
session.curSceneNumId = t.SceneNumId; session.curSceneNumId = t.SceneNumId;
session.position = new Vector3f(req.Position);
session.rotation = new Vector3f(req.Rotation);
session.sceneLoadState = Player.SceneLoadState.Loading;
session.Send(ScMsgId.ScSceneTeleport, t); session.Send(ScMsgId.ScSceneTeleport, t);
} }

View File

@ -0,0 +1,19 @@
using Campofinale.Network;
using Campofinale.Protocol;
using Campofinale.Utils;
using static Campofinale.Resource.ResourceManager;
namespace Campofinale.Packets.Cs
{
public class HandleCsSceneTeleportFinish
{
[Server.Handler(CsMsgId.CsSceneTeleportFinish)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsSceneTeleportFinish req = packet.DecodeBody<CsSceneTeleportFinish>();
session.sceneLoadState=Player.SceneLoadState.OK;
}
}
}

View File

@ -11,7 +11,7 @@ namespace Campofinale.Packets.Sc
ScFactoryModifyChapterNodes edit = new() ScFactoryModifyChapterNodes edit = new()
{ {
ChapterId = chapterId, ChapterId = chapterId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds()/1000, Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(),
Nodes = Nodes =
{ {
node.ToProto() node.ToProto()
@ -24,7 +24,7 @@ namespace Campofinale.Packets.Sc
ScFactoryModifyChapterNodes edit = new() ScFactoryModifyChapterNodes edit = new()
{ {
ChapterId = chapterId, ChapterId = chapterId,
Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds() / 1000, Tms = DateTime.UtcNow.ToUnixTimestampMilliseconds(),
RemoveNodes = RemoveNodes =
{ {
nodeId nodeId

View File

@ -78,6 +78,10 @@ namespace Campofinale.Packets.Sc
}; };
} }
if(op.OpType == FactoryOpType.MoveItemCacheToBag)
{
proto.MoveItemCacheToBag = new();
}
proto.Index=op.Index; proto.Index=op.Index;
SetData(ScMsgId.ScFactoryOpRet, proto); SetData(ScMsgId.ScFactoryOpRet, proto);
} }

View File

@ -759,5 +759,24 @@ namespace Campofinale
} }
} }
public void RestTeam()
{
GetCurTeam().ForEach(chara =>
{
chara.curHp = chara.CalcAttributes()[AttributeType.MaxHp].val;
ScCharSyncStatus state = new ScCharSyncStatus()
{
Objid = chara.guid,
IsDead = chara.curHp < 1,
BattleInfo = new()
{
Hp = chara.curHp,
Ultimatesp = chara.ultimateSp
}
};
Send(ScMsgId.ScCharSyncStatus, state);
});
}
} }
} }